2010-03-01 23:00:15 +01:00
|
|
|
#include "test_utils.h"
|
|
|
|
#include "gtest/gtest.h"
|
2010-03-03 00:37:12 +01:00
|
|
|
#include "gmock/gmock.h"
|
2010-03-01 23:00:15 +01:00
|
|
|
|
|
|
|
#include "librarybackend.h"
|
2010-03-03 00:37:12 +01:00
|
|
|
#include "song.h"
|
2010-03-01 23:00:15 +01:00
|
|
|
|
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
|
|
|
|
|
|
#include <QtDebug>
|
|
|
|
#include <QThread>
|
2010-03-03 01:33:31 +01:00
|
|
|
#include <QSignalSpy>
|
2010-03-01 23:00:15 +01:00
|
|
|
|
|
|
|
using ::testing::_;
|
2010-03-02 14:35:39 +01:00
|
|
|
using ::testing::AtMost;
|
2010-03-01 23:00:15 +01:00
|
|
|
using ::testing::Invoke;
|
|
|
|
using ::testing::Return;
|
|
|
|
|
|
|
|
void PrintTo(const ::QString& str, std::ostream& os) {
|
|
|
|
os << str.toStdString();
|
|
|
|
}
|
|
|
|
|
|
|
|
class LibraryBackendTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
virtual void SetUp() {
|
2010-03-03 00:37:12 +01:00
|
|
|
backend_.reset(new LibraryBackend(NULL, ":memory:"));
|
|
|
|
|
|
|
|
connection_name_ = "thread_" + QString::number(
|
|
|
|
reinterpret_cast<quint64>(QThread::currentThread()));
|
|
|
|
database_ = QSqlDatabase::database(connection_name_);
|
2010-03-01 23:00:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TearDown() {
|
|
|
|
// Make sure Qt does not re-use the connection.
|
2010-03-03 00:37:12 +01:00
|
|
|
database_ = QSqlDatabase();
|
|
|
|
QSqlDatabase::removeDatabase(connection_name_);
|
2010-03-01 23:00:15 +01:00
|
|
|
}
|
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
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_filename("foo.mp3");
|
|
|
|
ret.set_mtime(0);
|
|
|
|
ret.set_ctime(0);
|
|
|
|
ret.set_filesize(0);
|
|
|
|
return ret;
|
2010-03-02 14:35:39 +01:00
|
|
|
}
|
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
boost::scoped_ptr<LibraryBackend> backend_;
|
|
|
|
QString connection_name_;
|
|
|
|
QSqlDatabase database_;
|
2010-03-02 14:35:39 +01:00
|
|
|
};
|
2010-03-01 23:00:15 +01:00
|
|
|
|
|
|
|
TEST_F(LibraryBackendTest, DatabaseInitialises) {
|
2010-03-03 00:37:12 +01:00
|
|
|
// Check that these tables exist
|
|
|
|
QStringList tables = database_.tables();
|
|
|
|
EXPECT_TRUE(tables.contains("songs"));
|
|
|
|
EXPECT_TRUE(tables.contains("directories"));
|
|
|
|
ASSERT_TRUE(tables.contains("schema_version"));
|
|
|
|
|
|
|
|
// Check the schema version is correct
|
|
|
|
QSqlQuery q("SELECT version FROM schema_version", database_);
|
|
|
|
ASSERT_TRUE(q.exec());
|
|
|
|
ASSERT_TRUE(q.next());
|
2010-03-08 19:07:18 +01:00
|
|
|
EXPECT_EQ(LibraryBackend::kSchemaVersion, q.value(0).toInt());
|
2010-03-03 00:37:12 +01:00
|
|
|
EXPECT_FALSE(q.next());
|
2010-03-01 23:00:15 +01:00
|
|
|
}
|
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
TEST_F(LibraryBackendTest, EmptyDatabase) {
|
|
|
|
// Check the database is empty to start with
|
|
|
|
QStringList artists = backend_->GetAllArtists();
|
|
|
|
EXPECT_TRUE(artists.isEmpty());
|
2010-03-02 14:35:39 +01:00
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
LibraryBackend::AlbumList albums = backend_->GetAllAlbums();
|
|
|
|
EXPECT_TRUE(albums.isEmpty());
|
2010-03-01 23:00:15 +01:00
|
|
|
}
|
2010-03-02 14:35:39 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(LibraryBackendTest, AddDirectory) {
|
|
|
|
QSignalSpy spy(backend_.get(), SIGNAL(DirectoriesDiscovered(DirectoryList)));
|
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
backend_->AddDirectory("/test");
|
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
// Check the signal was emitted correctly
|
|
|
|
ASSERT_EQ(1, spy.count());
|
|
|
|
DirectoryList list = spy[0][0].value<DirectoryList>();
|
|
|
|
ASSERT_EQ(1, list.size());
|
|
|
|
EXPECT_EQ("/test", list[0].path);
|
|
|
|
EXPECT_EQ(1, list[0].id);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryBackendTest, RemoveDirectory) {
|
|
|
|
// Add a directory
|
|
|
|
Directory dir;
|
|
|
|
dir.id = 1;
|
|
|
|
dir.path = "/test";
|
|
|
|
backend_->AddDirectory(dir.path);
|
|
|
|
|
|
|
|
QSignalSpy spy(backend_.get(), SIGNAL(DirectoriesDeleted(DirectoryList)));
|
|
|
|
|
|
|
|
// Remove the directory again
|
|
|
|
backend_->RemoveDirectory(dir);
|
|
|
|
|
|
|
|
// Check the signal was emitted correctly
|
|
|
|
ASSERT_EQ(1, spy.count());
|
|
|
|
DirectoryList list = spy[0][0].value<DirectoryList>();
|
|
|
|
ASSERT_EQ(1, list.size());
|
|
|
|
EXPECT_EQ("/test", list[0].path);
|
|
|
|
EXPECT_EQ(1, list[0].id);
|
|
|
|
}
|
|
|
|
|
2010-03-03 02:39:39 +01:00
|
|
|
TEST_F(LibraryBackendTest, AddInvalidSong) {
|
|
|
|
// Adding a song without certain fields set should fail
|
|
|
|
backend_->AddDirectory("/test");
|
|
|
|
Song s;
|
|
|
|
s.set_directory_id(1);
|
|
|
|
|
|
|
|
QSignalSpy spy(backend_.get(), SIGNAL(Error(QString)));
|
|
|
|
|
|
|
|
backend_->AddOrUpdateSongs(SongList() << s);
|
|
|
|
ASSERT_EQ(1, spy.count()); spy.takeFirst();
|
|
|
|
|
|
|
|
s.set_filename("foo");
|
|
|
|
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(LibraryBackendTest, GetAlbumArtNonExistent) {
|
|
|
|
}
|
|
|
|
|
2010-03-22 17:03:24 +01:00
|
|
|
TEST_F(LibraryBackendTest, LikeWorksWithAllAscii) {
|
|
|
|
EXPECT_TRUE(LibraryBackend::Like("%ar%", "bar"));
|
|
|
|
EXPECT_FALSE(LibraryBackend::Like("%ar%", "foo"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryBackendTest, LikeWorksWithUnicode) {
|
|
|
|
EXPECT_TRUE(LibraryBackend::Like("%Снег%", "Снег"));
|
|
|
|
EXPECT_FALSE(LibraryBackend::Like("%Снег%", "foo"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryBackendTest, LikeAsciiCaseInsensitive) {
|
|
|
|
EXPECT_TRUE(LibraryBackend::Like("%ar%", "BAR"));
|
|
|
|
EXPECT_FALSE(LibraryBackend::Like("%ar%", "FOO"));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(LibraryBackendTest, LikeUnicodeCaseInsensitive) {
|
|
|
|
EXPECT_TRUE(LibraryBackend::Like("%снег%", "Снег"));
|
|
|
|
}
|
2010-03-03 01:33:31 +01:00
|
|
|
|
|
|
|
// Test adding a single song to the database, then getting various information
|
|
|
|
// back about it.
|
|
|
|
class SingleSong : public LibraryBackendTest {
|
|
|
|
protected:
|
|
|
|
virtual void SetUp() {
|
|
|
|
LibraryBackendTest::SetUp();
|
|
|
|
|
|
|
|
// Add a directory - this will get ID 1
|
|
|
|
backend_->AddDirectory("/test");
|
|
|
|
|
|
|
|
// Make a song in that directory
|
|
|
|
song_ = MakeDummySong(1);
|
|
|
|
song_.set_title("Title");
|
|
|
|
song_.set_artist("Artist");
|
|
|
|
song_.set_album("Album");
|
2010-03-03 01:49:44 +01:00
|
|
|
}
|
2010-03-03 01:33:31 +01:00
|
|
|
|
2010-03-03 01:49:44 +01:00
|
|
|
void AddDummySong() {
|
2010-03-03 01:33:31 +01:00
|
|
|
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 = added_spy[0][0].value<SongList>();
|
|
|
|
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_;
|
|
|
|
};
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-05 11:51:16 +01:00
|
|
|
TEST_F(SingleSong, GetSongWithNoAlbum) {
|
|
|
|
song_.set_album("");
|
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
|
|
|
|
|
|
|
EXPECT_EQ(1, backend_->GetAllArtists().size());
|
|
|
|
LibraryBackend::AlbumList albums = backend_->GetAllAlbums();
|
|
|
|
EXPECT_EQ(1, albums.size());
|
|
|
|
EXPECT_EQ("Artist", albums[0].artist);
|
|
|
|
EXPECT_EQ("", albums[0].album_name);
|
|
|
|
}
|
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, GetAllArtists) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
QStringList artists = backend_->GetAllArtists();
|
|
|
|
ASSERT_EQ(1, artists.size());
|
2010-03-03 01:33:31 +01:00
|
|
|
EXPECT_EQ(song_.artist(), artists[0]);
|
|
|
|
}
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, GetAllAlbums) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 00:37:12 +01:00
|
|
|
LibraryBackend::AlbumList albums = backend_->GetAllAlbums();
|
|
|
|
ASSERT_EQ(1, albums.size());
|
2010-03-03 01:33:31 +01:00
|
|
|
EXPECT_EQ(song_.album(), albums[0].album_name);
|
|
|
|
EXPECT_EQ(song_.artist(), albums[0].artist);
|
|
|
|
}
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, GetAlbumsByArtist) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
LibraryBackend::AlbumList albums = backend_->GetAlbumsByArtist("Artist");
|
2010-03-03 00:37:12 +01:00
|
|
|
ASSERT_EQ(1, albums.size());
|
2010-03-03 01:33:31 +01:00
|
|
|
EXPECT_EQ(song_.album(), albums[0].album_name);
|
|
|
|
EXPECT_EQ(song_.artist(), albums[0].artist);
|
|
|
|
}
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, GetAlbumArt) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
LibraryBackend::Album album = backend_->GetAlbumArt("Artist", "Album");
|
|
|
|
EXPECT_EQ(song_.album(), album.album_name);
|
|
|
|
EXPECT_EQ(song_.artist(), album.artist);
|
|
|
|
}
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, GetSongs) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
SongList songs = backend_->GetSongs("Artist", "Album");
|
2010-03-03 00:37:12 +01:00
|
|
|
ASSERT_EQ(1, songs.size());
|
2010-03-03 01:33:31 +01:00
|
|
|
EXPECT_EQ(song_.album(), songs[0].album());
|
|
|
|
EXPECT_EQ(song_.artist(), songs[0].artist());
|
|
|
|
EXPECT_EQ(song_.title(), songs[0].title());
|
2010-03-03 00:37:12 +01:00
|
|
|
EXPECT_EQ(1, songs[0].id());
|
2010-03-03 01:33:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(SingleSong, GetSongById) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
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());
|
|
|
|
}
|
2010-03-03 00:37:12 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
TEST_F(SingleSong, FindSongsInDirectory) {
|
2010-03-03 19:38:20 +01:00
|
|
|
AddDummySong(); if (HasFatalFailure()) return;
|
2010-03-03 01:49:44 +01:00
|
|
|
|
2010-03-03 01:33:31 +01:00
|
|
|
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());
|
2010-03-03 00:37:12 +01:00
|
|
|
}
|
2010-03-03 19:38:20 +01:00
|
|
|
|
|
|
|
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 = added_spy[0][0].value<SongList>();
|
|
|
|
SongList songs_deleted = deleted_spy[0][0].value<SongList>();
|
|
|
|
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 = deleted_spy[0][0].value<SongList>();
|
|
|
|
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());
|
|
|
|
|
|
|
|
LibraryBackend::AlbumList albums = backend_->GetAllAlbums();
|
|
|
|
EXPECT_EQ(0, albums.size());
|
|
|
|
}
|