Add tests (#193)

This commit is contained in:
Jonas Kvinge
2019-06-28 01:33:22 +02:00
committed by GitHub
parent b9f4407815
commit 60bd90848b
42 changed files with 3156 additions and 7 deletions

148
tests/src/closure_test.cpp Normal file
View File

@@ -0,0 +1,148 @@
#include "config.h"
#include <functional>
#include <memory>
#include <gtest/gtest.h>
#include <QObject>
#include <QPointer>
#include <QSharedPointer>
#include <QSignalSpy>
#include "core/closure.h"
#include "test_utils.h"
TEST(ClosureTest, ClosureInvokesReceiver) {
TestQObject sender;
TestQObject receiver;
_detail::ClosureBase* closure = NewClosure(&sender, SIGNAL(Emitted()), &receiver, SLOT(Invoke()));
EXPECT_EQ(0, receiver.invoked());
sender.Emit();
EXPECT_EQ(1, receiver.invoked());
}
TEST(ClosureTest, ClosureDeletesSelf) {
TestQObject sender;
TestQObject receiver;
_detail::ClosureBase* closure = NewClosure(&sender, SIGNAL(Emitted()), &receiver, SLOT(Invoke()));
_detail::ObjectHelper* helper = closure->helper();
QSignalSpy spy(helper, SIGNAL(destroyed()));
EXPECT_EQ(0, receiver.invoked());
sender.Emit();
EXPECT_EQ(1, receiver.invoked());
EXPECT_EQ(0, spy.count());
QEventLoop loop;
QObject::connect(helper, SIGNAL(destroyed()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1, spy.count());
}
TEST(ClosureTest, ClosureDoesNotCrashWithSharedPointerSender) {
TestQObject receiver;
TestQObject* sender;
std::unique_ptr<QSignalSpy> spy;
QPointer<_detail::ObjectHelper> closure;
{
QSharedPointer<TestQObject> sender_shared(new TestQObject);
sender = sender_shared.data();
closure = QPointer<_detail::ObjectHelper>(NewClosure(sender_shared, SIGNAL(Emitted()), &receiver, SLOT(Invoke()))->helper());
spy.reset(new QSignalSpy(sender, SIGNAL(destroyed())));
}
ASSERT_EQ(0, receiver.invoked());
sender->Emit();
ASSERT_EQ(1, receiver.invoked());
ASSERT_EQ(0, spy->count());
QEventLoop loop;
QObject::connect(sender, SIGNAL(destroyed()), &loop, SLOT(quit()));
loop.exec();
ASSERT_EQ(1, spy->count());
EXPECT_TRUE(closure.isNull());
}
namespace {
void Foo(bool* called, int question, int* answer) {
*called = true;
*answer = question;
}
} // namespace
TEST(ClosureTest, ClosureWorksWithFunctionPointers) {
TestQObject sender;
bool called = false;
int question = 42;
int answer = 0;
NewClosure(&sender, SIGNAL(Emitted()), &Foo, &called, question, &answer);
EXPECT_FALSE(called);
sender.Emit();
EXPECT_TRUE(called);
EXPECT_EQ(question, answer);
}
TEST(ClosureTest, ClosureWorksWithStandardFunctions) {
TestQObject sender;
bool called = false;
int question = 42;
int answer = 0;
std::function<void(bool*,int,int*)> callback(&Foo);
NewClosure(&sender, SIGNAL(Emitted()), callback, &called, question, &answer);
EXPECT_FALSE(called);
sender.Emit();
EXPECT_TRUE(called);
EXPECT_EQ(question, answer);
}
namespace {
class Bar {
public:
explicit Bar(int a) : foo_(a) {}
bool Foo(int* answer) {
*answer = foo_;
return true;
}
private:
int foo_;
};
}
TEST(ClosureTest, ClosureWorksWithMemberFunctionPointers) {
TestQObject sender;
Bar receiver(42);
int q = 1;
NewClosure(&sender, SIGNAL(Emitted()), &receiver, &Bar::Foo, &q);
EXPECT_EQ(1, q);
sender.Emit();
EXPECT_EQ(42, q);
}
TEST(ClosureTest, ClosureCallsLambda) {
TestQObject sender;
bool called = false;
NewClosure(&sender, SIGNAL(Emitted()), [&called] () { called = true; });
EXPECT_FALSE(called);
sender.Emit();
EXPECT_TRUE(called);
}

View File

@@ -0,0 +1,370 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <memory>
#include <gtest/gtest.h>
#include <QFileInfo>
#include <QSignalSpy>
#include <QThread>
#include <QtDebug>
#include "test_utils.h"
#include "core/song.h"
#include "core/database.h"
#include "core/logging.h"
#include "collection/collectionbackend.h"
#include "collection/collection.h"
namespace {
class CollectionBackendTest : public ::testing::Test {
protected:
virtual void SetUp() {
database_.reset(new MemoryDatabase(nullptr));
backend_.reset(new CollectionBackend);
backend_->Init(database_.get(), SCollection::kSongsTable, SCollection::kDirsTable, SCollection::kSubdirsTable, SCollection::kFtsTable);
}
Song MakeDummySong(int directory_id) {
// Returns a valid song with all the required fields set
Song ret;
ret.set_directory_id(directory_id);
ret.set_url(QUrl::fromLocalFile("foo.flac"));
ret.set_mtime(1);
ret.set_ctime(1);
ret.set_filesize(1);
return ret;
}
std::shared_ptr<Database> database_;
std::unique_ptr<CollectionBackend> backend_;
};
TEST_F(CollectionBackendTest, EmptyDatabase) {
// Check the database is empty to start with
QStringList artists = backend_->GetAllArtists();
EXPECT_TRUE(artists.isEmpty());
CollectionBackend::AlbumList albums = backend_->GetAllAlbums();
EXPECT_TRUE(albums.isEmpty());
}
TEST_F(CollectionBackendTest, AddDirectory) {
QSignalSpy spy(backend_.get(), SIGNAL(DirectoryDiscovered(Directory, SubdirectoryList)));
backend_->AddDirectory("/tmp");
// Check the signal was emitted correctly
ASSERT_EQ(1, spy.count());
Directory dir = spy[0][0].value<Directory>();
EXPECT_EQ(QFileInfo("/tmp").canonicalFilePath(), dir.path);
EXPECT_EQ(1, dir.id);
EXPECT_EQ(0, spy[0][1].value<SubdirectoryList>().size());
}
TEST_F(CollectionBackendTest, RemoveDirectory) {
// Add a directory
Directory dir;
dir.id = 1;
dir.path = "/tmp";
backend_->AddDirectory(dir.path);
QSignalSpy spy(backend_.get(), SIGNAL(DirectoryDeleted(Directory)));
// Remove the directory again
backend_->RemoveDirectory(dir);
// Check the signal was emitted correctly
ASSERT_EQ(1, spy.count());
dir = spy[0][0].value<Directory>();
EXPECT_EQ("/tmp", dir.path);
EXPECT_EQ(1, dir.id);
}
TEST_F(CollectionBackendTest, AddInvalidSong) {
// Adding a song without certain fields set should fail
backend_->AddDirectory("/tmp");
Song s;
//s.set_url(QUrl::fromLocalFile("foo.flac"));
s.set_directory_id(1);
QSignalSpy spy(database_.get(), SIGNAL(Error(QString)));
backend_->AddOrUpdateSongs(SongList() << s);
//ASSERT_EQ(1, spy.count()); spy.takeFirst();
s.set_url(QUrl::fromLocalFile("foo.flac"));
backend_->AddOrUpdateSongs(SongList() << s);
//ASSERT_EQ(1, spy.count()); spy.takeFirst();
s.set_filesize(100);
backend_->AddOrUpdateSongs(SongList() << s);
//ASSERT_EQ(1, spy.count()); spy.takeFirst();
s.set_mtime(100);
backend_->AddOrUpdateSongs(SongList() << s);
//ASSERT_EQ(1, spy.count()); spy.takeFirst();
s.set_ctime(100);
backend_->AddOrUpdateSongs(SongList() << s);
ASSERT_EQ(0, spy.count());
}
TEST_F(CollectionBackendTest, GetAlbumArtNonExistent) {
}
// Test adding a single song to the database, then getting various information back about it.
class SingleSong : public CollectionBackendTest {
protected:
virtual void SetUp() {
CollectionBackendTest::SetUp();
// Add a directory - this will get ID 1
backend_->AddDirectory("/tmp");
// Make a song in that directory
song_ = MakeDummySong(1);
song_.set_title("Title");
song_.set_artist("Artist");
song_.set_album("Album");
song_.set_url(QUrl::fromLocalFile("foo.flac"));
}
void AddDummySong() {
QSignalSpy added_spy(backend_.get(), SIGNAL(SongsDiscovered(SongList)));
QSignalSpy deleted_spy(backend_.get(), SIGNAL(SongsDeleted(SongList)));
// Add the song
backend_->AddOrUpdateSongs(SongList() << song_);
// Check the correct signals were emitted
EXPECT_EQ(0, deleted_spy.count());
ASSERT_EQ(1, added_spy.count());
SongList list = *(reinterpret_cast<SongList*>(added_spy[0][0].data()));
ASSERT_EQ(1, list.count());
EXPECT_EQ(song_.title(), list[0].title());
EXPECT_EQ(song_.artist(), list[0].artist());
EXPECT_EQ(song_.album(), list[0].album());
EXPECT_EQ(1, list[0].id());
EXPECT_EQ(1, list[0].directory_id());
}
Song song_;
};
TEST_F(SingleSong, GetSongWithNoAlbum) {
song_.set_album("");
AddDummySong(); if (HasFatalFailure()) return;
EXPECT_EQ(1, backend_->GetAllArtists().size());
CollectionBackend::AlbumList albums = backend_->GetAllAlbums();
//EXPECT_EQ(1, albums.size());
//EXPECT_EQ("Artist", albums[0].artist);
//EXPECT_EQ("", albums[0].album_name);
}
TEST_F(SingleSong, GetAllArtists) {
AddDummySong(); if (HasFatalFailure()) return;
QStringList artists = backend_->GetAllArtists();
ASSERT_EQ(1, artists.size());
EXPECT_EQ(song_.artist(), artists[0]);
}
TEST_F(SingleSong, GetAllAlbums) {
AddDummySong(); if (HasFatalFailure()) return;
CollectionBackend::AlbumList albums = backend_->GetAllAlbums();
ASSERT_EQ(1, albums.size());
EXPECT_EQ(song_.album(), albums[0].album_name);
EXPECT_EQ(song_.artist(), albums[0].artist);
}
TEST_F(SingleSong, GetAlbumsByArtist) {
AddDummySong(); if (HasFatalFailure()) return;
CollectionBackend::AlbumList albums = backend_->GetAlbumsByArtist("Artist");
ASSERT_EQ(1, albums.size());
EXPECT_EQ(song_.album(), albums[0].album_name);
EXPECT_EQ(song_.artist(), albums[0].artist);
}
TEST_F(SingleSong, GetAlbumArt) {
AddDummySong(); if (HasFatalFailure()) return;
CollectionBackend::Album album = backend_->GetAlbumArt("Artist", "AlbumArtist", "Album");
EXPECT_EQ(song_.album(), album.album_name);
EXPECT_EQ(song_.artist(), album.artist);
}
TEST_F(SingleSong, GetSongs) {
AddDummySong(); if (HasFatalFailure()) return;
SongList songs = backend_->GetSongs("Artist", "Album");
ASSERT_EQ(1, songs.size());
EXPECT_EQ(song_.album(), songs[0].album());
EXPECT_EQ(song_.artist(), songs[0].artist());
EXPECT_EQ(song_.title(), songs[0].title());
EXPECT_EQ(1, songs[0].id());
}
TEST_F(SingleSong, GetSongById) {
AddDummySong(); if (HasFatalFailure()) return;
Song song = backend_->GetSongById(1);
EXPECT_EQ(song_.album(), song.album());
EXPECT_EQ(song_.artist(), song.artist());
EXPECT_EQ(song_.title(), song.title());
EXPECT_EQ(1, song.id());
}
TEST_F(SingleSong, FindSongsInDirectory) {
AddDummySong(); if (HasFatalFailure()) return;
SongList songs = backend_->FindSongsInDirectory(1);
ASSERT_EQ(1, songs.size());
EXPECT_EQ(song_.album(), songs[0].album());
EXPECT_EQ(song_.artist(), songs[0].artist());
EXPECT_EQ(song_.title(), songs[0].title());
EXPECT_EQ(1, songs[0].id());
}
TEST_F(SingleSong, UpdateSong) {
AddDummySong(); if (HasFatalFailure()) return;
Song new_song(song_);
new_song.set_id(1);
new_song.set_title("A different title");
QSignalSpy deleted_spy(backend_.get(), SIGNAL(SongsDeleted(SongList)));
QSignalSpy added_spy(backend_.get(), SIGNAL(SongsDiscovered(SongList)));
backend_->AddOrUpdateSongs(SongList() << new_song);
ASSERT_EQ(1, added_spy.size());
ASSERT_EQ(1, deleted_spy.size());
SongList songs_added = *(reinterpret_cast<SongList*>(added_spy[0][0].data()));
SongList songs_deleted = *(reinterpret_cast<SongList*>(deleted_spy[0][0].data()));
ASSERT_EQ(1, songs_added.size());
ASSERT_EQ(1, songs_deleted.size());
EXPECT_EQ("Title", songs_deleted[0].title());
EXPECT_EQ("A different title", songs_added[0].title());
EXPECT_EQ(1, songs_deleted[0].id());
EXPECT_EQ(1, songs_added[0].id());
}
TEST_F(SingleSong, DeleteSongs) {
AddDummySong(); if (HasFatalFailure()) return;
Song new_song(song_);
new_song.set_id(1);
QSignalSpy deleted_spy(backend_.get(), SIGNAL(SongsDeleted(SongList)));
backend_->DeleteSongs(SongList() << new_song);
ASSERT_EQ(1, deleted_spy.size());
SongList songs_deleted = *(reinterpret_cast<SongList*>(deleted_spy[0][0].data()));
ASSERT_EQ(1, songs_deleted.size());
EXPECT_EQ("Title", songs_deleted[0].title());
EXPECT_EQ(1, songs_deleted[0].id());
// Check we can't retreive that song any more
Song song = backend_->GetSongById(1);
EXPECT_FALSE(song.is_valid());
EXPECT_EQ(-1, song.id());
// And the artist or album shouldn't show up either
QStringList artists = backend_->GetAllArtists();
EXPECT_EQ(0, artists.size());
CollectionBackend::AlbumList albums = backend_->GetAllAlbums();
EXPECT_EQ(0, albums.size());
}
TEST_F(SingleSong, MarkSongsUnavailable) {
AddDummySong(); if (HasFatalFailure()) return;
Song new_song(song_);
new_song.set_id(1);
QSignalSpy deleted_spy(backend_.get(), SIGNAL(SongsDeleted(SongList)));
backend_->MarkSongsUnavailable(SongList() << new_song);
ASSERT_EQ(1, deleted_spy.size());
SongList songs_deleted = *(reinterpret_cast<SongList*>(deleted_spy[0][0].data()));
ASSERT_EQ(1, songs_deleted.size());
EXPECT_EQ("Title", songs_deleted[0].title());
EXPECT_EQ(1, songs_deleted[0].id());
// Check the song is marked as deleted.
Song song = backend_->GetSongById(1);
EXPECT_TRUE(song.is_valid());
EXPECT_TRUE(song.is_unavailable());
// And the artist or album shouldn't show up either
QStringList artists = backend_->GetAllArtists();
EXPECT_EQ(0, artists.size());
CollectionBackend::AlbumList albums = backend_->GetAllAlbums();
EXPECT_EQ(0, albums.size());
}
} // namespace

View File

@@ -0,0 +1,335 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <memory>
#include <gtest/gtest.h>
#include <QString>
#include <QUrl>
#include <QThread>
#include <QSignalSpy>
#include <QSortFilterProxyModel>
#include <QtDebug>
#include "test_utils.h"
#include "core/database.h"
#include "collection/collectionmodel.h"
#include "collection/collectionbackend.h"
#include "collection/collection.h"
namespace {
class CollectionModelTest : public ::testing::Test {
protected:
void SetUp() {
database_.reset(new MemoryDatabase(nullptr));
backend_.reset(new CollectionBackend);
backend_->Init(database_.get(), SCollection::kSongsTable, SCollection::kDirsTable, SCollection::kSubdirsTable, SCollection::kFtsTable);
model_.reset(new CollectionModel(backend_.get(), nullptr));
added_dir_ = false;
model_sorted_.reset(new QSortFilterProxyModel);
model_sorted_->setSourceModel(model_.get());
model_sorted_->setSortRole(CollectionModel::Role_SortText);
model_sorted_->setDynamicSortFilter(true);
model_sorted_->sort(0);
}
Song AddSong(Song& song) {
song.set_directory_id(1);
if (song.mtime() == -1) song.set_mtime(1);
if (song.ctime() == -1) song.set_ctime(1);
if (song.url().isEmpty()) song.set_url(QUrl("file:///tmp/foo"));
if (song.filesize() == -1) song.set_filesize(1);
if (!added_dir_) {
backend_->AddDirectory("/tmp");
added_dir_ = true;
}
backend_->AddOrUpdateSongs(SongList() << song);
return song;
}
Song AddSong(const QString& title, const QString& artist, const QString& album, int length) {
Song song;
song.Init(title, artist, album, length);
return AddSong(song);
}
std::shared_ptr<Database> database_;
std::unique_ptr<CollectionBackend> backend_;
std::unique_ptr<CollectionModel> model_;
std::unique_ptr<QSortFilterProxyModel> model_sorted_;
bool added_dir_;
};
TEST_F(CollectionModelTest, Initialisation) {
EXPECT_EQ(0, model_->rowCount(QModelIndex()));
}
TEST_F(CollectionModelTest, WithInitialArtists) {
AddSong("Title", "Artist 1", "Album", 123);
AddSong("Title", "Artist 2", "Album", 123);
AddSong("Title", "Foo", "Album", 123);
model_->Init(false);
ASSERT_EQ(5, model_sorted_->rowCount(QModelIndex()));
EXPECT_EQ("A", model_sorted_->index(0, 0, QModelIndex()).data().toString());
EXPECT_EQ("Artist 1", model_sorted_->index(1, 0, QModelIndex()).data().toString());
EXPECT_EQ("Artist 2", model_sorted_->index(2, 0, QModelIndex()).data().toString());
EXPECT_EQ("F", model_sorted_->index(3, 0, QModelIndex()).data().toString());
EXPECT_EQ("Foo", model_sorted_->index(4, 0, QModelIndex()).data().toString());
}
TEST_F(CollectionModelTest, CompilationAlbums) {
Song song;
song.Init("Title", "Artist", "Album", 123);
song.set_compilation(true);
AddSong(song);
model_->Init(false);
model_->fetchMore(model_->index(0, 0));
ASSERT_EQ(1, model_->rowCount(QModelIndex()));
QModelIndex va_index = model_->index(0, 0, QModelIndex());
EXPECT_EQ("Various artists", va_index.data().toString());
EXPECT_TRUE(model_->hasChildren(va_index));
ASSERT_EQ(model_->rowCount(va_index), 1);
QModelIndex album_index = model_->index(0, 0, va_index);
EXPECT_EQ(model_->data(album_index).toString(), "Album");
EXPECT_TRUE(model_->hasChildren(album_index));
}
TEST_F(CollectionModelTest, NumericHeaders) {
AddSong("Title", "1artist", "Album", 123);
AddSong("Title", "2artist", "Album", 123);
AddSong("Title", "0artist", "Album", 123);
AddSong("Title", "zartist", "Album", 123);
model_->Init(false);
ASSERT_EQ(6, model_sorted_->rowCount(QModelIndex()));
EXPECT_EQ("0-9", model_sorted_->index(0, 0, QModelIndex()).data().toString());
EXPECT_EQ("0artist", model_sorted_->index(1, 0, QModelIndex()).data().toString());
EXPECT_EQ("1artist", model_sorted_->index(2, 0, QModelIndex()).data().toString());
EXPECT_EQ("2artist", model_sorted_->index(3, 0, QModelIndex()).data().toString());
EXPECT_EQ("Z", model_sorted_->index(4, 0, QModelIndex()).data().toString());
EXPECT_EQ("zartist", model_sorted_->index(5, 0, QModelIndex()).data().toString());
}
TEST_F(CollectionModelTest, MixedCaseHeaders) {
AddSong("Title", "Artist", "Album", 123);
AddSong("Title", "artist", "Album", 123);
model_->Init(false);
ASSERT_EQ(3, model_sorted_->rowCount(QModelIndex()));
EXPECT_EQ("A", model_sorted_->index(0, 0, QModelIndex()).data().toString());
EXPECT_EQ("Artist", model_sorted_->index(1, 0, QModelIndex()).data().toString());
EXPECT_EQ("artist", model_sorted_->index(2, 0, QModelIndex()).data().toString());
}
TEST_F(CollectionModelTest, UnknownArtists) {
AddSong("Title", "", "Album", 123);
model_->Init(false);
model_->fetchMore(model_->index(0, 0));
ASSERT_EQ(1, model_->rowCount(QModelIndex()));
QModelIndex unknown_index = model_->index(0, 0, QModelIndex());
EXPECT_EQ("Unknown", unknown_index.data().toString());
ASSERT_EQ(1, model_->rowCount(unknown_index));
EXPECT_EQ("Album", model_->index(0, 0, unknown_index).data().toString());
}
TEST_F(CollectionModelTest, UnknownAlbums) {
AddSong("Title", "Artist", "", 123);
AddSong("Title", "Artist", "Album", 123);
model_->Init(false);
model_->fetchMore(model_->index(0, 0));
QModelIndex artist_index = model_->index(0, 0, QModelIndex());
ASSERT_EQ(2, model_->rowCount(artist_index));
QModelIndex unknown_album_index = model_->index(0, 0, artist_index);
QModelIndex real_album_index = model_->index(1, 0, artist_index);
EXPECT_EQ("Unknown", unknown_album_index.data().toString());
EXPECT_EQ("Album", real_album_index.data().toString());
}
TEST_F(CollectionModelTest, VariousArtistSongs) {
SongList songs;
for (int i=0 ; i < 4 ; ++i) {
QString n = QString::number(i+1);
Song song;
song.Init("Title " + n, "Artist " + n, "Album", 0);
songs << song;
}
// Different ways of putting songs in "Various Artist". Make sure they all work
songs[0].set_compilation_detected(true);
songs[1].set_compilation(true);
songs[2].set_compilation_on(true);
songs[3].set_compilation_detected(true); songs[3].set_artist("Various Artists");
for (int i=0 ; i<4 ; ++i)
AddSong(songs[i]);
model_->Init(false);
QModelIndex artist_index = model_->index(0, 0, QModelIndex());
model_->fetchMore(artist_index);
ASSERT_EQ(1, model_->rowCount(artist_index));
QModelIndex album_index = model_->index(0, 0, artist_index);
model_->fetchMore(album_index);
ASSERT_EQ(4, model_->rowCount(album_index));
EXPECT_EQ("Artist 1 - Title 1", model_->index(0, 0, album_index).data().toString());
EXPECT_EQ("Artist 2 - Title 2", model_->index(1, 0, album_index).data().toString());
EXPECT_EQ("Artist 3 - Title 3", model_->index(2, 0, album_index).data().toString());
EXPECT_EQ("Title 4", model_->index(3, 0, album_index).data().toString());
}
TEST_F(CollectionModelTest, RemoveSongsLazyLoaded) {
Song one = AddSong("Title 1", "Artist", "Album", 123); one.set_id(1);
Song two = AddSong("Title 2", "Artist", "Album", 123); two.set_id(2);
AddSong("Title 3", "Artist", "Album", 123);
model_->Init(false);
// Lazy load the items
QModelIndex artist_index = model_->index(0, 0, QModelIndex());
model_->fetchMore(artist_index);
ASSERT_EQ(1, model_->rowCount(artist_index));
QModelIndex album_index = model_->index(0, 0, artist_index);
model_->fetchMore(album_index);
ASSERT_EQ(3, model_->rowCount(album_index));
// Remove the first two songs
QSignalSpy spy_preremove(model_.get(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
QSignalSpy spy_remove(model_.get(), SIGNAL(rowsRemoved(QModelIndex,int,int)));
QSignalSpy spy_reset(model_.get(), SIGNAL(modelReset()));
backend_->DeleteSongs(SongList() << one << two);
ASSERT_EQ(2, spy_preremove.count());
ASSERT_EQ(2, spy_remove.count());
ASSERT_EQ(0, spy_reset.count());
artist_index = model_->index(0, 0, QModelIndex());
ASSERT_EQ(1, model_->rowCount(artist_index));
album_index = model_->index(0, 0, artist_index);
ASSERT_EQ(1, model_->rowCount(album_index));
EXPECT_EQ("Title 3", model_->index(0, 0, album_index).data().toString());
}
TEST_F(CollectionModelTest, RemoveSongsNotLazyLoaded) {
Song one = AddSong("Title 1", "Artist", "Album", 123); one.set_id(1);
Song two = AddSong("Title 2", "Artist", "Album", 123); two.set_id(2);
model_->Init(false);
// Remove the first two songs
QSignalSpy spy_preremove(model_.get(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
QSignalSpy spy_remove(model_.get(), SIGNAL(rowsRemoved(QModelIndex,int,int)));
QSignalSpy spy_reset(model_.get(), SIGNAL(modelReset()));
backend_->DeleteSongs(SongList() << one << two);
ASSERT_EQ(0, spy_preremove.count());
ASSERT_EQ(0, spy_remove.count());
ASSERT_EQ(1, spy_reset.count());
}
TEST_F(CollectionModelTest, RemoveEmptyAlbums) {
Song one = AddSong("Title 1", "Artist", "Album 1", 123); one.set_id(1);
Song two = AddSong("Title 2", "Artist", "Album 2", 123); two.set_id(2);
Song three = AddSong("Title 3", "Artist", "Album 2", 123); three.set_id(3);
model_->Init(false);
QModelIndex artist_index = model_->index(0, 0, QModelIndex());
model_->fetchMore(artist_index);
ASSERT_EQ(2, model_->rowCount(artist_index));
// Remove one song from each album
backend_->DeleteSongs(SongList() << one << two);
// Check the model
artist_index = model_->index(0, 0, QModelIndex());
model_->fetchMore(artist_index);
ASSERT_EQ(1, model_->rowCount(artist_index));
QModelIndex album_index = model_->index(0, 0, artist_index);
model_->fetchMore(album_index);
EXPECT_EQ("Album 2", album_index.data().toString());
ASSERT_EQ(1, model_->rowCount(album_index));
EXPECT_EQ("Title 3", model_->index(0, 0, album_index).data().toString());
}
TEST_F(CollectionModelTest, RemoveEmptyArtists) {
Song one = AddSong("Title", "Artist", "Album", 123); one.set_id(1);
model_->Init(false);
// Lazy load the items
QModelIndex artist_index = model_->index(0, 0, QModelIndex());
model_->fetchMore(artist_index);
ASSERT_EQ(1, model_->rowCount(artist_index));
QModelIndex album_index = model_->index(0, 0, artist_index);
model_->fetchMore(album_index);
ASSERT_EQ(1, model_->rowCount(album_index));
// The artist header is there too right?
ASSERT_EQ(2, model_->rowCount(QModelIndex()));
// Remove the song
backend_->DeleteSongs(SongList() << one);
// Everything should be gone - even the artist header
ASSERT_EQ(0, model_->rowCount(QModelIndex()));
}
} // namespace

View File

@@ -0,0 +1,169 @@
#include <functional>
#include <gtest/gtest.h>
#include <QThreadPool>
#include <QEventLoop>
#include <QFutureWatcher>
#include "core/concurrentrun.h"
#include "test_utils.h"
int f() {
return 1337;
}
TEST(ConcurrentRunTest, ConcurrentRun0StartAndWait) {
QThreadPool threadpool;
QFuture<int> future = ConcurrentRun::Run<int>(&threadpool, &f);
QFutureWatcher<int> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1337, watcher.result());
}
int g(int i) {
return ++i;
}
TEST(ConcurrentRunTest, ConcurrentRun1StartAndWait) {
QThreadPool threadpool;
int i = 1336;
QFuture<int> future = ConcurrentRun::Run<int, int>(&threadpool, &g, i);
QFutureWatcher<int> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1337, watcher.result());
}
int max(int i, int j) {
return (i > j ? i : j);
}
TEST(ConcurrentRunTest, ConcurrentRun2StartAndWait) {
int i = 10;
int j = 42;
QThreadPool threadpool;
QFuture<int> future = ConcurrentRun::Run<int, int, int>(&threadpool, &max, i, j);
QFutureWatcher<int> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(42, watcher.result());
}
int sum(int a, int b, int c) {
return a + b + c;
}
TEST(ConcurrentRunTest, ConcurrentRun3StartAndWait) {
int i = 10;
int j = 42;
int k = 50;
QThreadPool threadpool;
QFuture<int> future = ConcurrentRun::Run<int, int, int, int>(&threadpool, &sum, i, j, k);
QFutureWatcher<int> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(102, watcher.result());
}
void aFunction(int* n) {
*n = 1337;
}
void bFunction(int* n, int *m) {
aFunction(n);
*m = 1338;
}
void cFunction(int* n, int *m, int *o) {
bFunction(n, m);
*o = 1339;
}
TEST(ConcurrentRunTest, ConcurrentRunVoidFunction1Start) {
QThreadPool threadpool;
int n = 10;
QFuture<void> future = ConcurrentRun::Run<void, int*>(&threadpool, &aFunction, &n);
QFutureWatcher<void> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1337, n);
}
TEST(ConcurrentRunTest, ConcurrentRunVoidFunction2Start) {
QThreadPool threadpool;
int n = 10, m = 11;
QFuture<void> future = ConcurrentRun::Run<void, int*, int*>(&threadpool, &bFunction, &n, &m);
QFutureWatcher<void> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1337, n);
EXPECT_EQ(1338, m);
}
TEST(ConcurrentRunTest, ConcurrentRunVoidFunction3Start) {
QThreadPool threadpool;
int n = 10, m = 11, o = 12;
QFuture<void> future = ConcurrentRun::Run<void, int*, int*, int*>(&threadpool, &cFunction, &n, &m, &o);
QFutureWatcher<void> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(1337, n);
EXPECT_EQ(1338, m);
EXPECT_EQ(1339, o);
}
class A {
public:
void f(int* i) {
*i = *i + 1;
}
};
TEST(ConcurrentRunTest, ConcurrentRunVoidBindFunctionStart) {
QThreadPool threadpool;
A a;
int nb = 10;
QFuture<void> future = ConcurrentRun::Run<void>(&threadpool, std::bind(&A::f, &a, &nb));
QFutureWatcher<void> watcher;
watcher.setFuture(future);
QEventLoop loop;
QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
EXPECT_EQ(11, nb);
}

36
tests/src/logging_env.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LOGGING_ENV_H
#define LOGGING_ENV_H
#include <gtest/gtest.h>
#include "core/logging.h"
class LoggingEnvironment : public ::testing::Environment {
public:
void SetUp() {
logging::Init();
logging::SetLevels("*:4");
}
};
#endif // LOGGING_ENV_H

44
tests/src/main.cpp Normal file
View File

@@ -0,0 +1,44 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <gmock/gmock.h>
#include <QApplication>
#include "logging_env.h"
#include "metatypes_env.h"
#include "resources_env.h"
int main(int argc, char** argv) {
testing::InitGoogleMock(&argc, argv);
testing::AddGlobalTestEnvironment(new MetatypesEnvironment);
#ifdef GUI
QApplication a(argc, argv);
#else
QCoreApplication a(argc, argv);
#endif
testing::AddGlobalTestEnvironment(new ResourcesEnvironment);
testing::AddGlobalTestEnvironment(new LoggingEnvironment);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,181 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "gtest/gtest.h"
#include "test_utils.h"
#include "core/mergedproxymodel.h"
#include <QStandardItemModel>
#include <QSignalSpy>
class MergedProxyModelTest : public ::testing::Test {
protected:
void SetUp() {
merged_.setSourceModel(&source_);
}
QStandardItemModel source_;
MergedProxyModel merged_;
};
TEST_F(MergedProxyModelTest, Flat) {
source_.appendRow(new QStandardItem("one"));
source_.appendRow(new QStandardItem("two"));
ASSERT_EQ(2, merged_.rowCount(QModelIndex()));
QModelIndex one_i = merged_.index(0, 0, QModelIndex());
QModelIndex two_i = merged_.index(1, 0, QModelIndex());
EXPECT_EQ("one", one_i.data().toString());
EXPECT_EQ("two", two_i.data().toString());
EXPECT_FALSE(merged_.parent(one_i).isValid());
EXPECT_FALSE(merged_.hasChildren(one_i));
}
TEST_F(MergedProxyModelTest, Tree) {
QStandardItem* one = new QStandardItem("one");
QStandardItem* two = new QStandardItem("two");
source_.appendRow(one);
one->appendRow(two);
ASSERT_EQ(1, merged_.rowCount(QModelIndex()));
QModelIndex one_i = merged_.index(0, 0, QModelIndex());
ASSERT_EQ(1, merged_.rowCount(one_i));
QModelIndex two_i = merged_.index(0, 0, one_i);
EXPECT_EQ("one", one_i.data().toString());
EXPECT_EQ("two", two_i.data().toString());
EXPECT_EQ("one", two_i.parent().data().toString());
}
TEST_F(MergedProxyModelTest, Merged) {
source_.appendRow(new QStandardItem("one"));
QStandardItemModel submodel;
submodel.appendRow(new QStandardItem("two"));
merged_.AddSubModel(source_.index(0, 0, QModelIndex()), &submodel);
ASSERT_EQ(1, merged_.rowCount(QModelIndex()));
QModelIndex one_i = merged_.index(0, 0, QModelIndex());
EXPECT_EQ("one", merged_.data(one_i).toString());
EXPECT_TRUE(merged_.hasChildren(one_i));
ASSERT_EQ(1, merged_.rowCount(one_i));
QModelIndex two_i = merged_.index(0, 0, one_i);
EXPECT_EQ("two", merged_.data(two_i).toString());
EXPECT_EQ(0, merged_.rowCount(two_i));
EXPECT_FALSE(merged_.hasChildren(two_i));
}
TEST_F(MergedProxyModelTest, SourceInsert) {
QSignalSpy before_spy(&merged_, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
QSignalSpy after_spy(&merged_, SIGNAL(rowsInserted(QModelIndex,int,int)));
source_.appendRow(new QStandardItem("one"));
ASSERT_EQ(1, before_spy.count());
ASSERT_EQ(1, after_spy.count());
EXPECT_FALSE(before_spy[0][0].value<QModelIndex>().isValid());
EXPECT_EQ(0, before_spy[0][1].toInt());
EXPECT_EQ(0, before_spy[0][2].toInt());
EXPECT_FALSE(after_spy[0][0].value<QModelIndex>().isValid());
EXPECT_EQ(0, after_spy[0][1].toInt());
EXPECT_EQ(0, after_spy[0][2].toInt());
}
TEST_F(MergedProxyModelTest, SourceRemove) {
source_.appendRow(new QStandardItem("one"));
QSignalSpy before_spy(&merged_, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
QSignalSpy after_spy(&merged_, SIGNAL(rowsRemoved(QModelIndex,int,int)));
source_.removeRow(0, QModelIndex());
ASSERT_EQ(1, before_spy.count());
ASSERT_EQ(1, after_spy.count());
EXPECT_FALSE(before_spy[0][0].value<QModelIndex>().isValid());
EXPECT_EQ(0, before_spy[0][1].toInt());
EXPECT_EQ(0, before_spy[0][2].toInt());
EXPECT_FALSE(after_spy[0][0].value<QModelIndex>().isValid());
EXPECT_EQ(0, after_spy[0][1].toInt());
EXPECT_EQ(0, after_spy[0][2].toInt());
}
TEST_F(MergedProxyModelTest, SubInsert) {
source_.appendRow(new QStandardItem("one"));
QStandardItemModel submodel;
merged_.AddSubModel(source_.index(0, 0, QModelIndex()), &submodel);
QSignalSpy before_spy(&merged_, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
QSignalSpy after_spy(&merged_, SIGNAL(rowsInserted(QModelIndex,int,int)));
submodel.appendRow(new QStandardItem("two"));
ASSERT_EQ(1, before_spy.count());
ASSERT_EQ(1, after_spy.count());
EXPECT_EQ("one", before_spy[0][0].value<QModelIndex>().data());
EXPECT_EQ(0, before_spy[0][1].toInt());
EXPECT_EQ(0, before_spy[0][2].toInt());
EXPECT_EQ("one", after_spy[0][0].value<QModelIndex>().data());
EXPECT_EQ(0, after_spy[0][1].toInt());
EXPECT_EQ(0, after_spy[0][2].toInt());
}
TEST_F(MergedProxyModelTest, SubRemove) {
source_.appendRow(new QStandardItem("one"));
QStandardItemModel submodel;
merged_.AddSubModel(source_.index(0, 0, QModelIndex()), &submodel);
submodel.appendRow(new QStandardItem("two"));
QSignalSpy before_spy(&merged_, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)));
QSignalSpy after_spy(&merged_, SIGNAL(rowsRemoved(QModelIndex,int,int)));
submodel.removeRow(0, QModelIndex());
ASSERT_EQ(1, before_spy.count());
ASSERT_EQ(1, after_spy.count());
EXPECT_EQ("one", before_spy[0][0].value<QModelIndex>().data());
EXPECT_EQ(0, before_spy[0][1].toInt());
EXPECT_EQ(0, before_spy[0][2].toInt());
EXPECT_EQ("one", after_spy[0][0].value<QModelIndex>().data());
EXPECT_EQ(0, after_spy[0][1].toInt());
EXPECT_EQ(0, after_spy[0][2].toInt());
}

46
tests/src/metatypes_env.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef METATYPES_ENV_H
#define METATYPES_ENV_H
#include <gtest/gtest.h>
#include <QMetaType>
#include <QModelIndex>
#include "core/song.h"
#include "core/songloader.h"
#include "collection/directory.h"
class MetatypesEnvironment : public ::testing::Environment {
public:
void SetUp() {
qRegisterMetaType<Directory>("Directory");
qRegisterMetaType<DirectoryList>("DirectoryList");
qRegisterMetaType<Subdirectory>("Subdirectory");
qRegisterMetaType<SubdirectoryList>("SubdirectoryList");
qRegisterMetaType<SongList>("SongList");
qRegisterMetaType<QModelIndex>("QModelIndex");
qRegisterMetaType<SongLoader::Result>("SongLoader::Result");
}
};
#endif // RESOURCES_ENV_H

View File

@@ -0,0 +1,72 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MOCKCOLLECTIONBACKEND_H
#define MOCKCOLLECTIONBACKEND_H
#include <gmock/gmock.h>
#include "collection/collectionbackend.h"
class MockCollectionBackend : public CollectionBackendInterface {
public:
MOCK_CONST_METHOD0(songs_table, QString());
// Get a list of directories in the collection. Emits DirectoriesDiscovered.
MOCK_METHOD0(LoadDirectoriesAsync, void());
// Counts the songs in the collection.
MOCK_METHOD0(UpdateTotalSongCountAsync, void());
MOCK_METHOD0(UpdateTotalAlbumCountAsync, void());
MOCK_METHOD0(UpdateTotalArtistCountAsync, void());
MOCK_METHOD1(FindSongsInDirectory, SongList(int));
MOCK_METHOD1(SubdirsInDirectory, SubdirectoryList(int));
MOCK_METHOD0(GetAllDirectories, DirectoryList());
MOCK_METHOD3(ChangeDirPath, void(int, const QString&, const QString&));
MOCK_METHOD1(GetAllArtists, QStringList(const QueryOptions&));
MOCK_METHOD1(GetAllArtistsWithAlbums, QStringList(const QueryOptions&));
MOCK_METHOD3(GetSongs, SongList(const QString&, const QString&, const QueryOptions&));
MOCK_METHOD2(GetCompilationSongs, SongList(const QString&, const QueryOptions&));
MOCK_METHOD1(GetAllAlbums, AlbumList(const QueryOptions&));
MOCK_METHOD2(GetAlbumsByArtist, AlbumList(const QString&, const QueryOptions&));
MOCK_METHOD1(GetCompilationAlbums, AlbumList(const QueryOptions&));
MOCK_METHOD4(UpdateManualAlbumArtAsync, void(const QString&, const QString&, const QString&, const QString&));
MOCK_METHOD3(GetAlbumArt, Album(const QString&, const QString&, const QString&));
MOCK_METHOD1(GetSongById, Song(int));
MOCK_METHOD1(GetSongsByUrl, SongList(const QUrl&));
MOCK_METHOD2(GetSongByUrl, Song(const QUrl&, qint64));
MOCK_METHOD1(AddDirectory, void(const QString&));
MOCK_METHOD1(RemoveDirectory, void(const Directory&));
MOCK_METHOD1(ExecQuery, bool(CollectionQuery*));
MOCK_METHOD2(GetSongsByAlbum, SongList(const QString&, const QueryOptions&));
};
#endif // MOCKCOLLECTIONBACKEND_H

View File

@@ -0,0 +1,137 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "mock_networkaccessmanager.h"
#include <algorithm>
#include <QtGlobal>
#include <QMap>
#include <QByteArray>
#include <QString>
#include <QIODevice>
#include <QNetworkRequest>
#include <QUrlQuery>
#include <QtDebug>
using std::min;
using ::testing::MakeMatcher;
using ::testing::Matcher;
using ::testing::MatcherInterface;
using ::testing::MatchResultListener;
using ::testing::Return;
class RequestForUrlMatcher : public MatcherInterface<const QNetworkRequest&> {
public:
RequestForUrlMatcher(const QString& contains, const QMap<QString, QString>& expected_params)
: contains_(contains), expected_params_(expected_params) {}
virtual ~RequestForUrlMatcher() {}
virtual bool Matches(const QNetworkRequest& req) const {
const QUrl& url = req.url();
if (!url.toString().contains(contains_)) {
return false;
}
QUrlQuery url_query(url);
for (QMap<QString, QString>::const_iterator it = expected_params_.constBegin(); it != expected_params_.constEnd(); ++it) {
if (!url_query.hasQueryItem(it.key()) || url_query.queryItemValue(it.key()) != it.value()) {
return false;
}
}
return true;
}
virtual bool MatchAndExplain(const QNetworkRequest& req, MatchResultListener* listener) const {
*listener << "which is " << req.url().toString().toUtf8().constData();
return Matches(req);
}
virtual void DescribeTo(::std::ostream* os) const {
*os << "matches url";
}
private:
QString contains_;
QMap<QString, QString> expected_params_;
};
inline Matcher<const QNetworkRequest&> RequestForUrl(const QString& contains, const QMap<QString, QString>& params) {
return MakeMatcher(new RequestForUrlMatcher(contains, params));
}
MockNetworkReply* MockNetworkAccessManager::ExpectGet(const QString& contains, const QMap<QString, QString>& expected_params, int status, const QByteArray& data) {
MockNetworkReply* reply = new MockNetworkReply(data);
reply->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status);
EXPECT_CALL(*this, createRequest(GetOperation, RequestForUrl(contains, expected_params), nullptr)). WillOnce(Return(reply));
return reply;
}
MockNetworkReply::MockNetworkReply()
: data_(nullptr) {
}
MockNetworkReply::MockNetworkReply(const QByteArray& data)
: data_(data),
pos_(0) {
}
void MockNetworkReply::SetData(const QByteArray& data) {
data_ = data;
pos_ = 0;
}
qint64 MockNetworkReply::readData(char* data, qint64 size) {
if (data_.size() == pos_) {
return -1;
}
qint64 bytes_to_read = min(data_.size() - pos_, size);
memcpy(data, data_.constData() + pos_, bytes_to_read);
pos_ += bytes_to_read;
return bytes_to_read;
}
qint64 MockNetworkReply::writeData(const char* data, qint64) {
ADD_FAILURE() << "Something tried to write to a QNetworkReply";
return -1;
}
void MockNetworkReply::Done() {
setOpenMode(QIODevice::ReadOnly);
emit finished();
}
void MockNetworkReply::setAttribute(QNetworkRequest::Attribute code, const QVariant& value) {
QNetworkReply::setAttribute(code, value);
}

View File

@@ -0,0 +1,74 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MOCK_NETWORKACCESSMANAGER_H
#define MOCK_NETWORKACCESSMANAGER_H
#include <QtGlobal>
#include <QMap>
#include <QByteArray>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include "test_utils.h"
#include "gmock/gmock.h"
// Usage:
// Create a MockNetworkAccessManager.
// Call ExpectGet() with appropriate expectations and the data you want back.
// This will return a MockNetworkReply*. When you are ready for the reply to arrive, call MockNetworkReply::Done().
class MockNetworkReply : public QNetworkReply {
Q_OBJECT
public:
MockNetworkReply();
MockNetworkReply(const QByteArray& data);
// Use these to set expectations.
void SetData(const QByteArray& data);
virtual void setAttribute(QNetworkRequest::Attribute code, const QVariant& value);
// Call this when you are ready for the finished() signal.
void Done();
protected:
MOCK_METHOD0(abort, void());
virtual qint64 readData(char* data, qint64);
virtual qint64 writeData(const char* data, qint64);
QByteArray data_;
qint64 pos_;
};
class MockNetworkAccessManager : public QNetworkAccessManager {
Q_OBJECT
public:
MockNetworkReply* ExpectGet(
const QString& contains, // A string that should be present in the URL.
const QMap<QString, QString>& params, // Required URL parameters.
int status, // Returned HTTP status code.
const QByteArray& ret_data); // Returned data.
protected:
MOCK_METHOD3(createRequest, QNetworkReply*(Operation, const QNetworkRequest&, QIODevice*));
};
#endif // MOCK_NETWORKACCESSMANAGER_H

View File

@@ -0,0 +1,28 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "core/song.h"
#include "mock_playlistitem.h"
using ::testing::_;
using ::testing::Return;
MockPlaylistItem::MockPlaylistItem() : PlaylistItem(Song::Source_LocalFile) {}

View File

@@ -0,0 +1,50 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MOCK_PLAYLISTITEM_H
#define MOCK_PLAYLISTITEM_H
#include <gmock/gmock.h>
#include <QVariant>
#include <QUrl>
#include "core/song.h"
#include "core/settingsprovider.h"
#include "collection/sqlrow.h"
#include "playlist/playlistitem.h"
class MockPlaylistItem : public PlaylistItem {
public:
MockPlaylistItem();
MOCK_CONST_METHOD0(options, Options());
MOCK_METHOD1(InitFromQuery, bool(const SqlRow& settings));
MOCK_METHOD0(Reload, void());
MOCK_CONST_METHOD0(Metadata, Song());
MOCK_CONST_METHOD0(Url, QUrl());
MOCK_METHOD1(SetTemporaryMetadata, void(const Song& metadata));
MOCK_METHOD0(ClearTemporaryMetadata, void());
MOCK_METHOD1(DatabaseValue, QVariant(DatabaseColumn));
};
#endif // MOCK_PLAYLISTITEM_H

View File

@@ -0,0 +1,54 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MOCK_SETTINGSPROVIDER_H
#define MOCK_SETTINGSPROVIDER_H
#include "core/settingsprovider.h"
#include <gmock/gmock.h>
class MockSettingsProvider : public SettingsProvider {
public:
MOCK_METHOD1(set_group, void(const char* group));
MOCK_CONST_METHOD2(value, QVariant(const QString& key, const QVariant& default_value));
MOCK_METHOD2(setValue, void(const QString& key, const QVariant& value));
MOCK_METHOD1(beginReadArray, int(const QString& prefix));
MOCK_METHOD2(beginWriteArray, void(const QString& prefix, int size));
MOCK_METHOD1(setArrayIndex, void(int i));
MOCK_METHOD0(endArray, void());
};
class DummySettingsProvider : public SettingsProvider {
public:
DummySettingsProvider() {}
void set_group(const char *group) {}
QVariant value(const QString&, const QVariant& = QVariant()) const { return QVariant(); }
void setValue(const QString&, const QVariant&) {}
int beginReadArray(const QString&) { return 0; }
void beginWriteArray(const QString&, int = -1) {}
void setArrayIndex(int) {}
void endArray() {}
};
#endif // MOCK_SETTINGSPROVIDER_H

View File

@@ -0,0 +1,173 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <gtest/gtest.h>
#include "test_utils.h"
#include "organise/organiseformat.h"
#include "core/timeconstants.h"
#include "core/song.h"
#include "core/logging.h"
#include <QUrl>
class OrganiseFormatTest : public ::testing::Test {
protected:
OrganiseFormat format_;
Song song_;
};
TEST_F(OrganiseFormatTest, BasicReplace) {
song_.set_title("title");
song_.set_album("album");
song_.set_artist("artist");
song_.set_albumartist("albumartist");
song_.set_track(321);
song_.set_disc(789);
song_.set_year(2010);
song_.set_originalyear(1995);
song_.set_genre("genre");
song_.set_composer("composer");
song_.set_performer("performer");
song_.set_grouping("grouping");
song_.set_comment("comment");
song_.set_length_nanosec(987 * kNsecPerSec);
song_.set_samplerate(654);
song_.set_bitdepth(32);
song_.set_bitrate(123);
format_.set_format("%album %albumartist %artist %bitrate %comment %composer %performer %grouping %disc %genre %length %samplerate %bitdepth %title %track %year");
ASSERT_TRUE(format_.IsValid());
EXPECT_EQ("album_albumartist_artist_123_comment_composer_performer_grouping_789_genre_987_654_32_title_321_2010", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, Extension) {
song_.set_url(QUrl("file:///some/path/filename.flac"));
format_.set_format("%extension");
ASSERT_TRUE(format_.IsValid());
EXPECT_EQ("flac", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, ArtistInitial) {
song_.set_artist("bob");
format_.set_format("%artistinitial");
ASSERT_TRUE(format_.IsValid());
EXPECT_EQ("B", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, AlbumArtistInitial) {
song_.set_albumartist("bob");
format_.set_format("%artistinitial");
ASSERT_TRUE(format_.IsValid());
EXPECT_EQ("B", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, InvalidTag) {
format_.set_format("%invalid");
EXPECT_FALSE(format_.IsValid());
}
TEST_F(OrganiseFormatTest, Blocks) {
format_.set_format("Before{Inside%year}After");
ASSERT_TRUE(format_.IsValid());
song_.set_year(-1);
EXPECT_EQ("BeforeAfter", format_.GetFilenameForSong(song_));
song_.set_year(0);
EXPECT_EQ("BeforeAfter", format_.GetFilenameForSong(song_));
song_.set_year(123);
EXPECT_EQ("BeforeInside123After", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, ReplaceSpaces) {
song_.set_title("The Song Title");
format_.set_format("The Format String %title");
format_.set_replace_spaces(false);
EXPECT_EQ("The Format String The Song Title", format_.GetFilenameForSong(song_));
format_.set_replace_spaces(true);
EXPECT_EQ("The_Format_String_The_Song_Title", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, ReplaceNonAscii) {
song_.set_artist(QString::fromUtf8("Röyksopp"));
format_.set_format("%artist");
format_.set_remove_non_ascii(false);
EXPECT_EQ(QString::fromUtf8("Röyksopp"), format_.GetFilenameForSong(song_));
format_.set_remove_non_ascii(true);
EXPECT_EQ("Royksopp", format_.GetFilenameForSong(song_));
song_.set_artist(QString::fromUtf8("Владимир Высоцкий"));
EXPECT_EQ("_________________", format_.GetFilenameForSong(song_));
}
TEST_F(OrganiseFormatTest, TrackNumberPadding) {
format_.set_format("%track");
song_.set_track(9);
EXPECT_EQ("09", format_.GetFilenameForSong(song_));
song_.set_track(99);
EXPECT_EQ("99", format_.GetFilenameForSong(song_));
song_.set_track(999);
EXPECT_EQ("999", format_.GetFilenameForSong(song_));
song_.set_track(0);
EXPECT_EQ("", format_.GetFilenameForSong(song_));
}
#if 0
TEST_F(OrganiseFormatTest, ReplaceSlashes) {
format_.set_format("%title");
song_.set_title("foo/bar\\baz");
qLog(Debug) << format_.GetFilenameForSong(song_);
EXPECT_EQ("foo_bar_baz", format_.GetFilenameForSong(song_));
}
#endif

543
tests/src/playlist_test.cpp Normal file
View File

@@ -0,0 +1,543 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <memory>
#include <gtest/gtest.h>
#include "test_utils.h"
#include "collection/collectionplaylistitem.h"
#include "playlist/playlist.h"
#include "mock_settingsprovider.h"
#include "mock_playlistitem.h"
#include <QtDebug>
#include <QUndoStack>
using std::shared_ptr;
using ::testing::Return;
namespace {
class PlaylistTest : public ::testing::Test {
protected:
PlaylistTest()
: playlist_(nullptr, nullptr, nullptr, 1),
sequence_(nullptr, new DummySettingsProvider)
{
}
void SetUp() {
playlist_.set_sequence(&sequence_);
}
MockPlaylistItem* MakeMockItem(const QString& title, const QString& artist = QString(), const QString& album = QString(), int length = 123) const {
Song metadata;
metadata.Init(title, artist, album, length);
MockPlaylistItem* ret = new MockPlaylistItem;
EXPECT_CALL(*ret, Metadata()).WillRepeatedly(Return(metadata));
return ret;
}
shared_ptr<PlaylistItem> MakeMockItemP(const QString& title, const QString& artist = QString(), const QString& album = QString(), int length = 123) const {
return shared_ptr<PlaylistItem>(MakeMockItem(title, artist, album, length));
}
Playlist playlist_;
PlaylistSequence sequence_;
};
TEST_F(PlaylistTest, Basic) {
EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
}
TEST_F(PlaylistTest, InsertItems) {
MockPlaylistItem* item = MakeMockItem("Title", "Artist", "Album", 123);
shared_ptr<PlaylistItem> item_ptr(item);
// Insert the item
EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
playlist_.InsertItems(PlaylistItemList() << item_ptr, -1);
ASSERT_EQ(1, playlist_.rowCount(QModelIndex()));
// Get the metadata
EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
EXPECT_EQ("Artist", playlist_.data(playlist_.index(0, Playlist::Column_Artist)));
EXPECT_EQ("Album", playlist_.data(playlist_.index(0, Playlist::Column_Album)));
EXPECT_EQ(123, playlist_.data(playlist_.index(0, Playlist::Column_Length)));
}
TEST_F(PlaylistTest, Indexes) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
// Start "playing" track 1
playlist_.set_current_row(0);
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ("One", playlist_.current_item()->Metadata().title());
EXPECT_EQ(-1, playlist_.previous_row());
EXPECT_EQ(1, playlist_.next_row());
// Stop playing
EXPECT_EQ(0, playlist_.last_played_row());
playlist_.set_current_row(-1);
EXPECT_EQ(0, playlist_.last_played_row());
EXPECT_EQ(-1, playlist_.current_row());
// Play track 2
playlist_.set_current_row(1);
EXPECT_EQ(1, playlist_.current_row());
EXPECT_EQ("Two", playlist_.current_item()->Metadata().title());
EXPECT_EQ(0, playlist_.previous_row());
EXPECT_EQ(2, playlist_.next_row());
// Play track 3
playlist_.set_current_row(2);
EXPECT_EQ(2, playlist_.current_row());
EXPECT_EQ("Three", playlist_.current_item()->Metadata().title());
EXPECT_EQ(1, playlist_.previous_row());
EXPECT_EQ(-1, playlist_.next_row());
}
TEST_F(PlaylistTest, RepeatPlaylist) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Playlist);
playlist_.set_current_row(0);
EXPECT_EQ(1, playlist_.next_row());
playlist_.set_current_row(1);
EXPECT_EQ(2, playlist_.next_row());
playlist_.set_current_row(2);
EXPECT_EQ(0, playlist_.next_row());
}
TEST_F(PlaylistTest, RepeatTrack) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Track);
playlist_.set_current_row(0);
EXPECT_EQ(0, playlist_.next_row());
}
TEST_F(PlaylistTest, RepeatAlbum) {
playlist_.InsertItems(PlaylistItemList()
<< MakeMockItemP("One", "Album one")
<< MakeMockItemP("Two", "Album two")
<< MakeMockItemP("Three", "Album one"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.sequence()->SetRepeatMode(PlaylistSequence::Repeat_Album);
playlist_.set_current_row(0);
EXPECT_EQ(2, playlist_.next_row());
playlist_.set_current_row(2);
EXPECT_EQ(0, playlist_.next_row());
}
TEST_F(PlaylistTest, RemoveBeforeCurrent) {
playlist_.InsertItems(PlaylistItemList()
<< MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
// Remove a row before the currently playing track
playlist_.set_current_row(2);
EXPECT_EQ(2, playlist_.current_row());
playlist_.removeRow(1, QModelIndex());
EXPECT_EQ(1, playlist_.current_row());
EXPECT_EQ(1, playlist_.last_played_row());
EXPECT_EQ(0, playlist_.previous_row());
EXPECT_EQ(-1, playlist_.next_row());
}
TEST_F(PlaylistTest, RemoveAfterCurrent) {
playlist_.InsertItems(PlaylistItemList()
<< MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
// Remove a row after the currently playing track
playlist_.set_current_row(0);
EXPECT_EQ(0, playlist_.current_row());
playlist_.removeRow(1, QModelIndex());
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ(0, playlist_.last_played_row());
EXPECT_EQ(-1, playlist_.previous_row());
EXPECT_EQ(1, playlist_.next_row());
playlist_.set_current_row(1);
EXPECT_EQ(-1, playlist_.next_row());
}
TEST_F(PlaylistTest, RemoveCurrent) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
// Remove the currently playing track's row
playlist_.set_current_row(1);
EXPECT_EQ(1, playlist_.current_row());
playlist_.removeRow(1, QModelIndex());
EXPECT_EQ(-1, playlist_.current_row());
EXPECT_EQ(-1, playlist_.last_played_row());
EXPECT_EQ(-1, playlist_.previous_row());
EXPECT_EQ(0, playlist_.next_row());
}
TEST_F(PlaylistTest, InsertBeforeCurrent) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.set_current_row(1);
EXPECT_EQ(1, playlist_.current_row());
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Four"), 0);
ASSERT_EQ(4, playlist_.rowCount(QModelIndex()));
EXPECT_EQ(2, playlist_.current_row());
EXPECT_EQ(2, playlist_.last_played_row());
EXPECT_EQ(1, playlist_.previous_row());
EXPECT_EQ(3, playlist_.next_row());
EXPECT_EQ("Four", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
EXPECT_EQ("One", playlist_.data(playlist_.index(1, Playlist::Column_Title)));
}
TEST_F(PlaylistTest, InsertAfterCurrent) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.set_current_row(1);
EXPECT_EQ(1, playlist_.current_row());
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Four"), 2);
ASSERT_EQ(4, playlist_.rowCount(QModelIndex()));
EXPECT_EQ(1, playlist_.current_row());
EXPECT_EQ(1, playlist_.last_played_row());
EXPECT_EQ(0, playlist_.previous_row());
EXPECT_EQ(2, playlist_.next_row());
EXPECT_EQ("Two", playlist_.data(playlist_.index(1, Playlist::Column_Title)));
EXPECT_EQ("Four", playlist_.data(playlist_.index(2, Playlist::Column_Title)));
EXPECT_EQ("Three", playlist_.data(playlist_.index(3, Playlist::Column_Title)));
}
TEST_F(PlaylistTest, Clear) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.set_current_row(1);
EXPECT_EQ(1, playlist_.current_row());
playlist_.Clear();
EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
EXPECT_EQ(-1, playlist_.current_row());
EXPECT_EQ(-1, playlist_.last_played_row());
EXPECT_EQ(-1, playlist_.previous_row());
EXPECT_EQ(-1, playlist_.next_row());
}
TEST_F(PlaylistTest, UndoAdd) {
EXPECT_FALSE(playlist_.undo_stack()->canUndo());
EXPECT_FALSE(playlist_.undo_stack()->canRedo());
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
EXPECT_FALSE(playlist_.undo_stack()->canRedo());
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
playlist_.undo_stack()->undo();
EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
EXPECT_FALSE(playlist_.undo_stack()->canUndo());
ASSERT_TRUE(playlist_.undo_stack()->canRedo());
playlist_.undo_stack()->redo();
EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
EXPECT_FALSE(playlist_.undo_stack()->canRedo());
EXPECT_TRUE(playlist_.undo_stack()->canUndo());
EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
}
TEST_F(PlaylistTest, UndoMultiAdd) {
// Add 1 item
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One"));
// Add 2 items
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Two") << MakeMockItemP("Three"));
// Undo adding 2 items
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
EXPECT_EQ("add 2 songs", playlist_.undo_stack()->undoText());
playlist_.undo_stack()->undo();
// Undo adding 1 item
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
EXPECT_EQ("add 1 songs", playlist_.undo_stack()->undoText());
playlist_.undo_stack()->undo();
EXPECT_FALSE(playlist_.undo_stack()->canUndo());
}
#if 0
TEST_F(PlaylistTest, UndoRemove) {
EXPECT_FALSE(playlist_.undo_stack()->canUndo());
EXPECT_FALSE(playlist_.undo_stack()->canRedo());
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
playlist_.removeRow(0);
EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
EXPECT_FALSE(playlist_.undo_stack()->canRedo());
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
playlist_.undo_stack()->undo();
//EXPECT_EQ(1, playlist_.rowCount(QModelIndex()));
//ASSERT_TRUE(playlist_.undo_stack()->canRedo());
//EXPECT_EQ("Title", playlist_.data(playlist_.index(0, Playlist::Column_Title)));
//playlist_.undo_stack()->redo();
//EXPECT_EQ(0, playlist_.rowCount(QModelIndex()));
//EXPECT_FALSE(playlist_.undo_stack()->canRedo());
//EXPECT_TRUE(playlist_.undo_stack()->canUndo());
}
TEST_F(PlaylistTest, UndoMultiRemove) {
// Add 3 items
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
// Remove 1 item
playlist_.removeRow(1); // Item "Two"
// Remove 2 items
playlist_.removeRows(0, 2); // "One" and "Three"
ASSERT_EQ(0, playlist_.rowCount(QModelIndex()));
// Undo removing all 3 items
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
EXPECT_EQ("remove 3 songs", playlist_.undo_stack()->undoText());
playlist_.undo_stack()->undo();
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
}
#endif
TEST_F(PlaylistTest, UndoClear) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("One") << MakeMockItemP("Two") << MakeMockItemP("Three"));
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
playlist_.Clear();
ASSERT_EQ(0, playlist_.rowCount(QModelIndex()));
ASSERT_TRUE(playlist_.undo_stack()->canUndo());
EXPECT_EQ("remove 3 songs", playlist_.undo_stack()->undoText());
playlist_.undo_stack()->undo();
ASSERT_EQ(3, playlist_.rowCount(QModelIndex()));
}
#if 0
TEST_F(PlaylistTest, UndoRemoveCurrent) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
playlist_.set_current_row(0);
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ(0, playlist_.last_played_row());
playlist_.removeRow(0);
EXPECT_EQ(-1, playlist_.current_row());
EXPECT_EQ(-1, playlist_.last_played_row());
playlist_.undo_stack()->undo();
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ(0, playlist_.last_played_row());
}
TEST_F(PlaylistTest, UndoRemoveOldCurrent) {
playlist_.InsertItems(PlaylistItemList() << MakeMockItemP("Title"));
playlist_.set_current_row(0);
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ(0, playlist_.last_played_row());
playlist_.removeRow(0);
EXPECT_EQ(-1, playlist_.current_row());
EXPECT_EQ(-1, playlist_.last_played_row());
playlist_.set_current_row(-1);
playlist_.undo_stack()->undo();
EXPECT_EQ(0, playlist_.current_row());
EXPECT_EQ(0, playlist_.last_played_row());
}
TEST_F(PlaylistTest, ShuffleThenNext) {
// Add 100 items
PlaylistItemList items;
for (int i=0 ; i<100 ; ++i)
items << MakeMockItemP("Item " + QString::number(i));
playlist_.InsertItems(items);
playlist_.set_current_row(0);
// Shuffle until the current index is not at the end
forever {
playlist_.Shuffle();
if (playlist_.current_row() != items.count()-1)
break;
}
int index = playlist_.current_row();
EXPECT_EQ("Item 0", playlist_.current_item()->Metadata().title());
EXPECT_EQ("Item 0", playlist_.data(playlist_.index(index, Playlist::Column_Title)));
EXPECT_EQ(index, playlist_.last_played_row());
EXPECT_EQ(index + 1, playlist_.next_row());
// Shuffle until the current index *is* at the end
forever {
playlist_.Shuffle();
if (playlist_.current_row() == items.count()-1)
break;
}
index = playlist_.current_row();
EXPECT_EQ("Item 0", playlist_.current_item()->Metadata().title());
EXPECT_EQ("Item 0", playlist_.data(playlist_.index(index, Playlist::Column_Title)));
EXPECT_EQ(index, playlist_.last_played_row());
EXPECT_EQ(-1, playlist_.next_row());
EXPECT_EQ(index-1, playlist_.previous_row());
}
#endif
TEST_F(PlaylistTest, CollectionIdMapSingle) {
Song song;
song.Init("title", "artist", "album", 123);
song.set_id(1);
PlaylistItemPtr item(new CollectionPlaylistItem(song));
playlist_.InsertItems(PlaylistItemList() << item);
EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(0).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
ASSERT_EQ(1, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(song.title(), playlist_.collection_items_by_id(1)[0]->Metadata().title());
playlist_.Clear();
EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
}
TEST_F(PlaylistTest, CollectionIdMapInvalid) {
Song invalid;
invalid.Init("title", "artist", "album", 123);
ASSERT_EQ(-1, invalid.id());
PlaylistItemPtr item(new CollectionPlaylistItem(invalid));
playlist_.InsertItems(PlaylistItemList() << item);
EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(0).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
}
TEST_F(PlaylistTest, CollectionIdMapMulti) {
Song one;
one.Init("title", "artist", "album", 123);
one.set_id(1);
Song two;
two.Init("title 2", "artist 2", "album 2", 123);
two.set_id(2);
PlaylistItemPtr item_one(new CollectionPlaylistItem(one));
PlaylistItemPtr item_two(new CollectionPlaylistItem(two));
PlaylistItemPtr item_three(new CollectionPlaylistItem(one));
playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three);
EXPECT_EQ(2, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(1, playlist_.collection_items_by_id(2).count());
playlist_.removeRow(1); // item_two
EXPECT_EQ(2, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
playlist_.removeRow(1); // item_three
EXPECT_EQ(1, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
playlist_.removeRow(0); // item_one
EXPECT_EQ(0, playlist_.collection_items_by_id(1).count());
EXPECT_EQ(0, playlist_.collection_items_by_id(2).count());
}
} // namespace

37
tests/src/resources_env.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef RESOURCES_ENV_H
#define RESOURCES_ENV_H
#include <gtest/gtest.h>
#include <QResource>
class ResourcesEnvironment : public ::testing::Environment {
public:
void SetUp() {
Q_INIT_RESOURCE(data);
Q_INIT_RESOURCE(translations);
Q_INIT_RESOURCE(testdata);
}
};
#endif // RESOURCES_ENV_H

147
tests/src/song_test.cpp Normal file
View File

@@ -0,0 +1,147 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <id3v2tag.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <QFile>
#include <QByteArray>
#include <QStringList>
#include <QTemporaryFile>
#include <QTextCodec>
#include <QRegExp>
#include "core/song.h"
#include "tagreader.h"
#include "test_utils.h"
namespace {
class SongTest : public ::testing::Test {
protected:
static void SetUpTestCase() {
// Return something from uninteresting mock functions.
testing::DefaultValue<TagLib::String>::Set("foobarbaz");
}
static Song ReadSongFromFile(const QString& filename) {
TagReader tag_reader;
Song song;
::pb::tagreader::SongMetadata pb_song;
// We need to init protobuf object from a Song object, to have default values initialized correctly.
song.ToProtobuf(&pb_song);
tag_reader.ReadFile(filename, &pb_song);
song.InitFromProtobuf(pb_song);
return song;
}
static void WriteSongToFile(const Song& song, const QString& filename) {
TagReader tag_reader;
::pb::tagreader::SongMetadata pb_song;
song.ToProtobuf(&pb_song);
tag_reader.SaveFile(filename, pb_song);
}
};
TEST_F(SongTest, TestAudioFileTagging) {
const QStringList files_to_test = QStringList() << ":/audio/strawberry.wav"
<< ":/audio/strawberry.flac"
<< ":/audio/strawberry.wv"
<< ":/audio/strawberry.oga"
<< ":/audio/strawberry.opus"
<< ":/audio/strawberry.spx"
<< ":/audio/strawberry.aif"
<< ":/audio/strawberry.m4a"
<< ":/audio/strawberry.mp4"
<< ":/audio/strawberry.mp3"
<< ":/audio/strawberry.asf";
for (const QString& test_filename : files_to_test) {
TemporaryResource r(test_filename);
Song song = ReadSongFromFile(r.fileName());
// Compare files
QFile orig_file(test_filename);
orig_file.open(QIODevice::ReadOnly);
EXPECT_TRUE(orig_file.isOpen());
QByteArray orig_file_data = orig_file.readAll();
QFile temp_file(r.fileName());
temp_file.open(QIODevice::ReadOnly);
EXPECT_TRUE(temp_file.isOpen());
QByteArray temp_file_data = temp_file.readAll();
EXPECT_TRUE(!orig_file_data.isEmpty());
EXPECT_TRUE(!temp_file_data.isEmpty());
EXPECT_TRUE(orig_file_data == temp_file_data);
if (test_filename.contains(QRegExp(".*\\.wav$"))) continue;
// Write tags
song.set_title("strawberry title");
song.set_artist("strawberry artist");
song.set_album("strawberry album");
song.set_albumartist("strawberry album artist");
song.set_composer("strawberry composer");
song.set_performer("strawberry performer");
song.set_grouping("strawberry grouping");
song.set_genre("strawberry genre");
song.set_comment("strawberry comment");
song.set_track(12);
song.set_disc(1234);
song.set_year(2019);
WriteSongToFile(song, r.fileName());
// Read tags
Song new_song = ReadSongFromFile(r.fileName());
EXPECT_EQ("strawberry title", new_song.title());
EXPECT_EQ("strawberry artist", new_song.artist());
EXPECT_EQ("strawberry album", new_song.album());
if (!test_filename.contains(QRegExp(".*\\.aif$")) && !test_filename.contains(QRegExp(".*\\.asf$"))) {
EXPECT_EQ("strawberry album artist", new_song.albumartist());
EXPECT_EQ("strawberry composer", new_song.composer());
if (!test_filename.contains(QRegExp(".*\\.mp4$")) && !test_filename.contains(QRegExp(".*\\.m4a$"))) {
EXPECT_EQ("strawberry performer", new_song.performer());
}
EXPECT_EQ("strawberry grouping", new_song.grouping());
EXPECT_EQ(1234, new_song.disc());
}
EXPECT_EQ("strawberry genre", new_song.genre());
if (!test_filename.contains(QRegExp(".*\\.asf$"))) {
EXPECT_EQ("strawberry comment", new_song.comment());
}
EXPECT_EQ(12, new_song.track());
EXPECT_EQ(2019, new_song.year());
}
}
} // namespace

View File

@@ -0,0 +1,79 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <memory>
#include <gtest/gtest.h>
#include <QTemporaryFile>
#include <QFileInfo>
#include <QString>
#include <QUrl>
#include <QtDebug>
#include "test_utils.h"
#include "playlist/songplaylistitem.h"
namespace {
class SongPlaylistItemTest : public ::testing::TestWithParam<const char*> {
protected:
SongPlaylistItemTest() : temp_file_(GetParam()) {}
void SetUp() {
// SongPlaylistItem::Url() checks if the file exists, so we need a real file
temp_file_.open();
absolute_file_name_ = QFileInfo(temp_file_.fileName()).absoluteFilePath();
song_.Init("Title", "Artist", "Album", 123);
song_.set_url(QUrl::fromLocalFile(absolute_file_name_));
item_.reset(new SongPlaylistItem(song_));
if (!absolute_file_name_.startsWith('/'))
absolute_file_name_.prepend('/');
}
Song song_;
QTemporaryFile temp_file_;
QString absolute_file_name_;
std::unique_ptr<SongPlaylistItem> item_;
};
INSTANTIATE_TEST_CASE_P(RealFiles, SongPlaylistItemTest, testing::Values(
"normalfile.flac",
"file with spaces.flac",
"file with # hash.flac",
"file with ? question.flac"
));
TEST_P(SongPlaylistItemTest, Url) {
QUrl expected;
expected.setScheme("file");
expected.setPath(absolute_file_name_);
EXPECT_EQ(expected, item_->Url());
}
} //namespace

16
tests/src/sqlite_test.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <gtest/gtest.h>
#include <sqlite3.h>
TEST(SqliteTest, FTS3SupportEnabled) {
sqlite3* db = nullptr;
int rc = sqlite3_open(":memory:", &db);
ASSERT_EQ(0, rc);
char* errmsg = nullptr;
rc = sqlite3_exec(db, "CREATE VIRTUAL TABLE foo USING fts3(content, TEXT)", nullptr, nullptr, &errmsg);
ASSERT_EQ(0, rc) << errmsg;
sqlite3_close(db);
}

87
tests/src/test_utils.cpp Normal file
View File

@@ -0,0 +1,87 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "test_utils.h"
#include <QObject>
#include <QIODevice>
#include <QDir>
#include <QNetworkRequest>
#include <QVariant>
#include <QString>
#include <QUrl>
std::ostream& operator<<(std::ostream& stream, const QString& str) {
stream << str.toStdString();
return stream;
}
std::ostream& operator <<(std::ostream& stream, const QUrl& url) {
stream << url.toString().toStdString();
return stream;
}
std::ostream& operator <<(std::ostream& stream, const QNetworkRequest& req) {
stream << req.url().toString().toStdString();
return stream;
}
std::ostream& operator <<(std::ostream& stream, const QVariant& var) {
stream << var.toString().toStdString();
return stream;
}
void PrintTo(const ::QString& str, std::ostream& os) {
os << str.toStdString();
}
void PrintTo(const ::QVariant& var, std::ostream& os) {
os << var.toString().toStdString();
}
void PrintTo(const ::QUrl& url, std::ostream& os) {
os << url.toString().toStdString();
}
TemporaryResource::TemporaryResource(const QString& filename) {
setFileTemplate(QDir::tempPath() + "/strawberry_test-XXXXXX." + filename.section('.', -1, -1));
open();
QFile resource(filename);
resource.open(QIODevice::ReadOnly);
write(resource.readAll());
reset();
}
TestQObject::TestQObject(QObject* parent)
: QObject(parent),
invoked_(0) {
}
void TestQObject::Emit() {
emit Emitted();
}
void TestQObject::Invoke() {
++invoked_;
}

87
tests/src/test_utils.h Normal file
View File

@@ -0,0 +1,87 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
#include <iostream>
#include <QMetaType>
#include <QModelIndex>
#include <QTemporaryFile>
class QNetworkRequest;
class QString;
class QUrl;
class QVariant;
std::ostream& operator <<(std::ostream& stream, const QString& str);
std::ostream& operator <<(std::ostream& stream, const QVariant& var);
std::ostream& operator <<(std::ostream& stream, const QUrl& url);
std::ostream& operator <<(std::ostream& stream, const QNetworkRequest& req);
template <typename T>
std::ostream& operator <<(std::ostream& stream, const QList<T>& list) {
stream << "QList(";
foreach (const T& item, list) {
stream << item << ",";
}
stream << ")";
return stream;
}
void PrintTo(const ::QString& str, std::ostream& os);
void PrintTo(const ::QVariant& var, std::ostream& os);
void PrintTo(const ::QUrl& url, std::ostream& os);
#define EXPOSE_SIGNAL0(n) \
void Emit##n() { emit n(); }
#define EXPOSE_SIGNAL1(n, t1) \
void Emit##n(const t1& a1) { emit n(a1); }
#define EXPOSE_SIGNAL2(n, t1, t2) \
void Emit##n(const t1& a1, const t2& a2) { emit n(a1, a2); }
Q_DECLARE_METATYPE(QModelIndex);
class TemporaryResource : public QTemporaryFile {
public:
TemporaryResource(const QString& filename);
};
class TestQObject : public QObject {
Q_OBJECT
public:
TestQObject(QObject* parent = 0);
void Emit();
int invoked() const { return invoked_; }
signals:
void Emitted();
public slots:
void Invoke();
private:
int invoked_;
};
#endif // TEST_UTILS_H

View File

@@ -0,0 +1,30 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define protected public
#include <QProgressBar>
#undef protected
#include "testobjectdecorators.h"
void TestObjectDecorators::initStyleOption(QProgressBar* self, QStyleOptionProgressBar* opt) {
self->initStyleOption(opt);
}

View File

@@ -0,0 +1,36 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TESTOBJECTDECORATORS_H
#define TESTOBJECTDECORATORS_H
#include <QObject>
class QProgressBar;
class QStyleOptionProgressBar;
class TestObjectDecorators : public QObject {
Q_OBJECT
public slots:
void initStyleOption(QProgressBar* self, QStyleOptionProgressBar* opt);
};
#endif // TESTOBJECTDECORATORS_H

View File

@@ -0,0 +1,50 @@
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <gtest/gtest.h>
#include <QString>
#include <QDateTime>
#include <QtDebug>
#include "test_utils.h"
#include "core/utilities.h"
TEST(UtilitiesTest, HmacFunctions) {
QString key("key");
QString data("The quick brown fox jumps over the lazy dog");
// Test Hmac Md5
QByteArray result_hash_md5 = Utilities::HmacMd5(key.toLocal8Bit(), data.toLocal8Bit()).toHex();
bool result_md5 = result_hash_md5 == QString("80070713463e7749b90c2dc24911e275");
EXPECT_TRUE(result_md5);
// Test Hmac Sha256
QByteArray result_hash_sha256 = Utilities::HmacSha256(key.toLocal8Bit(), data.toLocal8Bit()).toHex();
bool result_sha256 = result_hash_sha256 == QString("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8");
EXPECT_TRUE(result_sha256);
}
TEST(UtilitiesTest, ParseRFC822DateTim) {
QDateTime result_DateTime = Utilities::ParseRFC822DateTime(QString("22 Feb 2008 00:16:17 GMT"));
EXPECT_TRUE(result_DateTime.isValid());
result_DateTime = Utilities::ParseRFC822DateTime(QString("Thu, 13 Dec 2012 13:27:52 +0000"));
EXPECT_TRUE(result_DateTime.isValid());
result_DateTime = Utilities::ParseRFC822DateTime(QString("Mon, 12 March 2012 20:00:00 +0100"));
EXPECT_TRUE(result_DateTime.isValid());
}