Add tests (#193)
This commit is contained in:
parent
b9f4407815
commit
60bd90848b
@ -395,6 +395,7 @@ endif()
|
||||
# Subdirectories
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(dist)
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(ext/libstrawberry-common)
|
||||
add_subdirectory(ext/libstrawberry-tagreader)
|
||||
add_subdirectory(ext/strawberry-tagreader)
|
||||
|
@ -106,7 +106,8 @@ CollectionModel::CollectionModel(CollectionBackend *backend, Application *app, Q
|
||||
cover_loader_options_.pad_output_image_ = true;
|
||||
cover_loader_options_.scale_output_image_ = true;
|
||||
|
||||
connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)), SLOT(AlbumArtLoaded(quint64, QImage)));
|
||||
if (app_)
|
||||
connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)), SLOT(AlbumArtLoaded(quint64, QImage)));
|
||||
|
||||
//icon_cache_->setCacheDirectory(Utilities::GetConfigPath(Utilities::Path_CacheRoot) + "/pixmapcache");
|
||||
//icon_cache_->setMaximumCacheSize(CollectionModel::kIconCacheSize);
|
||||
@ -172,7 +173,8 @@ void CollectionModel::Init(bool async) {
|
||||
endResetModel();
|
||||
|
||||
// Show a loading indicator in the status bar too.
|
||||
init_task_id_ = app_->task_manager()->StartTask(tr("Loading songs"));
|
||||
if (app_)
|
||||
init_task_id_ = app_->task_manager()->StartTask(tr("Loading songs"));
|
||||
|
||||
ResetAsync();
|
||||
}
|
||||
@ -794,7 +796,8 @@ void CollectionModel::ResetAsyncQueryFinished(QFuture<CollectionModel::QueryResu
|
||||
PostQuery(root_, result, false);
|
||||
|
||||
if (init_task_id_ != -1) {
|
||||
app_->task_manager()->SetTaskFinished(init_task_id_);
|
||||
if (app_)
|
||||
app_->task_manager()->SetTaskFinished(init_task_id_);
|
||||
init_task_id_ = -1;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@
|
||||
using std::shared_ptr;
|
||||
using std::stable_sort;
|
||||
|
||||
const char *OrganiseDialog::kDefaultFormat = "%albumartist/%album{ (Disc %disc)}/{%track - }%albumartist - %album - %title.%extension";
|
||||
const char *OrganiseDialog::kDefaultFormat = "%albumartist/%album{ (Disc %disc)}/{%track - }{%albumartist - }%album{ (Disc %disc)} - %title.%extension";
|
||||
|
||||
const char *OrganiseDialog::kSettingsGroup = "OrganiseDialog";
|
||||
|
||||
OrganiseDialog::OrganiseDialog(TaskManager *task_manager, CollectionBackend *backend, QWidget *parent)
|
||||
|
@ -59,6 +59,8 @@ class OrganiseDialog : public QDialog {
|
||||
OrganiseDialog(TaskManager *task_manager, CollectionBackend *backend = nullptr, QWidget *parent = nullptr);
|
||||
~OrganiseDialog();
|
||||
|
||||
static const char *kDefaultFormat;
|
||||
|
||||
QSize sizeHint() const;
|
||||
|
||||
void SetDestinationModel(QAbstractItemModel *model, bool devices = false);
|
||||
@ -71,6 +73,8 @@ class OrganiseDialog : public QDialog {
|
||||
|
||||
void SetCopy(bool copy);
|
||||
|
||||
static Organise::NewSongInfoList ComputeNewSongsFilenames(const SongList &songs, const OrganiseFormat &format);
|
||||
|
||||
signals:
|
||||
void FileCopied(int);
|
||||
|
||||
@ -97,10 +101,7 @@ class OrganiseDialog : public QDialog {
|
||||
SongList LoadSongsBlocking(const QStringList &filenames);
|
||||
void SetLoadingSongs(bool loading);
|
||||
|
||||
static Organise::NewSongInfoList ComputeNewSongsFilenames(const SongList &songs, const OrganiseFormat &format);
|
||||
|
||||
private:
|
||||
static const char *kDefaultFormat;
|
||||
static const char *kSettingsGroup;
|
||||
|
||||
Ui_OrganiseDialog *ui_;
|
||||
|
99
tests/CMakeLists.txt
Normal file
99
tests/CMakeLists.txt
Normal file
@ -0,0 +1,99 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -fpermissive -Wno-c++11-narrowing -U__STRICT_ANSI__")
|
||||
|
||||
find_package(Qt5 ${QT_MIN_VERSION} COMPONENTS Test)
|
||||
find_package(GTest)
|
||||
find_library(GMOCK_LIBRARY gmock)
|
||||
|
||||
if(Qt5Test_FOUND AND GTEST_FOUND AND GMOCK_LIBRARY)
|
||||
|
||||
include_directories(${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS} ${QT_QTTEST_INCLUDE_DIR})
|
||||
include_directories(${TAGLIB_INCLUDE_DIRS})
|
||||
if(HAVE_GSTREAMER)
|
||||
link_directories(${GSTREAMER_LIBRARY_DIRS})
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_APP_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_AUDIO_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_BASE_INCLUDE_DIRS})
|
||||
include_directories(${GSTREAMER_TAG_INCLUDE_DIRS})
|
||||
endif()
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
include_directories(${CMAKE_BINARY_DIR}/src)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/tests/src)
|
||||
include_directories(${CMAKE_BINARY_DIR}/tests/src)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/strawberry-tagreader)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-common)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/ext/libstrawberry-tagreader)
|
||||
include_directories(${CMAKE_BINARY_DIR}/ext/libstrawberry-tagreader)
|
||||
if(HAVE_LIBGPOD)
|
||||
include_directories(${LIBGPOD_INCLUDE_DIRS})
|
||||
endif(HAVE_LIBGPOD)
|
||||
|
||||
add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1)
|
||||
|
||||
set(TESTUTILS-SOURCES
|
||||
src/mock_networkaccessmanager.cpp
|
||||
src/mock_playlistitem.cpp
|
||||
src/test_utils.cpp
|
||||
src/testobjectdecorators.cpp
|
||||
)
|
||||
|
||||
set(TESTUTILS-MOC-HEADERS src/mock_networkaccessmanager.h src/test_utils.h src/testobjectdecorators.h)
|
||||
|
||||
qt5_wrap_cpp(TESTUTILS-SOURCES-MOC ${TESTUTILS-MOC-HEADERS})
|
||||
|
||||
add_library(test_utils STATIC EXCLUDE_FROM_ALL ${TESTUTILS-SOURCES} ${TESTUTILS-SOURCES-MOC})
|
||||
target_link_libraries(test_utils ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${QT_LIBRARIES} ${Qt5Test_LIBRARIES})
|
||||
|
||||
add_custom_target(strawberry_test echo "Running Strawberry tests" WORKING_DIRECTORY ${CURRENT_BINARY_DIR})
|
||||
add_custom_target(build_tests WORKING_DIRECTORY ${CURRENT_BINARY_DIR})
|
||||
add_dependencies(strawberry_test build_tests)
|
||||
|
||||
qt5_add_resources(TEST-RESOURCE-SOURCES data/testdata.qrc)
|
||||
|
||||
add_library(test_gui_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp)
|
||||
target_link_libraries(test_gui_main strawberry_lib)
|
||||
set_target_properties(test_gui_main PROPERTIES COMPILE_DEFINITIONS GUI)
|
||||
|
||||
add_library(test_main STATIC EXCLUDE_FROM_ALL ${TEST-RESOURCE-SOURCES} src/main.cpp)
|
||||
target_link_libraries(test_main strawberry_lib)
|
||||
|
||||
# Given a file foo_test.cpp, creates a target foo_test and adds it to the test target.
|
||||
macro(add_test_file test_source gui_required)
|
||||
get_filename_component(TEST_NAME ${test_source} NAME_WE)
|
||||
add_executable(${TEST_NAME}
|
||||
EXCLUDE_FROM_ALL
|
||||
${test_source}
|
||||
)
|
||||
target_link_libraries(${TEST_NAME} ${GMOCK_LIBRARY} strawberry_lib test_utils Qt5::Test)
|
||||
set(GUI_REQUIRED ${gui_required})
|
||||
if (GUI_REQUIRED)
|
||||
target_link_libraries(${TEST_NAME} test_gui_main)
|
||||
else (GUI_REQUIRED)
|
||||
target_link_libraries(${TEST_NAME} test_main)
|
||||
endif (GUI_REQUIRED)
|
||||
|
||||
check_cxx_compiler_flag("-Wno-bool-conversions" SUPPORTS_NOBOOL)
|
||||
if (SUPPORTS_NOBOOL)
|
||||
set_target_properties(${TEST_NAME} PROPERTIES COMPILE_FLAGS "-Wno-bool-conversions")
|
||||
endif (SUPPORTS_NOBOOL)
|
||||
|
||||
add_custom_command(TARGET strawberry_test POST_BUILD
|
||||
COMMAND ./${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX})
|
||||
add_dependencies(build_tests ${TEST_NAME})
|
||||
endmacro (add_test_file)
|
||||
|
||||
add_test_file(src/utilities_test.cpp false)
|
||||
add_test_file(src/concurrentrun_test.cpp false)
|
||||
add_test_file(src/closure_test.cpp false)
|
||||
add_test_file(src/mergedproxymodel_test.cpp false)
|
||||
add_test_file(src/sqlite_test.cpp false)
|
||||
add_test_file(src/song_test.cpp false)
|
||||
add_test_file(src/collectionbackend_test.cpp false)
|
||||
add_test_file(src/collectionmodel_test.cpp true)
|
||||
add_test_file(src/playlist_test.cpp true)
|
||||
add_test_file(src/songplaylistitem_test.cpp false)
|
||||
add_test_file(src/organiseformat_test.cpp false)
|
||||
|
||||
endif() # Qt5Test_FOUND AND GTEST_FOUND AND GMOCK_LIBRARY
|
BIN
tests/data/audio/strawberry.aif
Normal file
BIN
tests/data/audio/strawberry.aif
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.asf
Normal file
BIN
tests/data/audio/strawberry.asf
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.flac
Normal file
BIN
tests/data/audio/strawberry.flac
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.m4a
Normal file
BIN
tests/data/audio/strawberry.m4a
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.mp3
Normal file
BIN
tests/data/audio/strawberry.mp3
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.mp4
Normal file
BIN
tests/data/audio/strawberry.mp4
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.oga
Normal file
BIN
tests/data/audio/strawberry.oga
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.opus
Normal file
BIN
tests/data/audio/strawberry.opus
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.spx
Normal file
BIN
tests/data/audio/strawberry.spx
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.wav
Normal file
BIN
tests/data/audio/strawberry.wav
Normal file
Binary file not shown.
BIN
tests/data/audio/strawberry.wv
Normal file
BIN
tests/data/audio/strawberry.wv
Normal file
Binary file not shown.
15
tests/data/testdata.qrc
Normal file
15
tests/data/testdata.qrc
Normal file
@ -0,0 +1,15 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>audio/strawberry.wav</file>
|
||||
<file>audio/strawberry.flac</file>
|
||||
<file>audio/strawberry.wv</file>
|
||||
<file>audio/strawberry.oga</file>
|
||||
<file>audio/strawberry.opus</file>
|
||||
<file>audio/strawberry.spx</file>
|
||||
<file>audio/strawberry.aif</file>
|
||||
<file>audio/strawberry.asf</file>
|
||||
<file>audio/strawberry.mp3</file>
|
||||
<file>audio/strawberry.m4a</file>
|
||||
<file>audio/strawberry.mp4</file>
|
||||
</qresource>
|
||||
</RCC>
|
148
tests/src/closure_test.cpp
Normal file
148
tests/src/closure_test.cpp
Normal 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);
|
||||
|
||||
}
|
370
tests/src/collectionbackend_test.cpp
Normal file
370
tests/src/collectionbackend_test.cpp
Normal 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
|
335
tests/src/collectionmodel_test.cpp
Normal file
335
tests/src/collectionmodel_test.cpp
Normal 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
|
169
tests/src/concurrentrun_test.cpp
Normal file
169
tests/src/concurrentrun_test.cpp
Normal 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
36
tests/src/logging_env.h
Normal 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
44
tests/src/main.cpp
Normal 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();
|
||||
|
||||
}
|
181
tests/src/mergedproxymodel_test.cpp
Normal file
181
tests/src/mergedproxymodel_test.cpp
Normal 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
46
tests/src/metatypes_env.h
Normal 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
|
72
tests/src/mock_collectionbackend.h
Normal file
72
tests/src/mock_collectionbackend.h
Normal 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
|
137
tests/src/mock_networkaccessmanager.cpp
Normal file
137
tests/src/mock_networkaccessmanager.cpp
Normal 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);
|
||||
}
|
74
tests/src/mock_networkaccessmanager.h
Normal file
74
tests/src/mock_networkaccessmanager.h
Normal 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
|
28
tests/src/mock_playlistitem.cpp
Normal file
28
tests/src/mock_playlistitem.cpp
Normal 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) {}
|
50
tests/src/mock_playlistitem.h
Normal file
50
tests/src/mock_playlistitem.h
Normal 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
|
54
tests/src/mock_settingsprovider.h
Normal file
54
tests/src/mock_settingsprovider.h
Normal 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
|
173
tests/src/organiseformat_test.cpp
Normal file
173
tests/src/organiseformat_test.cpp
Normal 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
543
tests/src/playlist_test.cpp
Normal 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
37
tests/src/resources_env.h
Normal 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
147
tests/src/song_test.cpp
Normal 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
|
79
tests/src/songplaylistitem_test.cpp
Normal file
79
tests/src/songplaylistitem_test.cpp
Normal 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
16
tests/src/sqlite_test.cpp
Normal 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
87
tests/src/test_utils.cpp
Normal 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
87
tests/src/test_utils.h
Normal 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
|
30
tests/src/testobjectdecorators.cpp
Normal file
30
tests/src/testobjectdecorators.cpp
Normal 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);
|
||||
}
|
36
tests/src/testobjectdecorators.h
Normal file
36
tests/src/testobjectdecorators.h
Normal 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
|
50
tests/src/utilities_test.cpp
Normal file
50
tests/src/utilities_test.cpp
Normal 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());
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user