mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-18 12:28:31 +01:00
Add test for AlbumCoverFetcher.
Comes with infrastructure for testing network requests.
This commit is contained in:
parent
15797e07c6
commit
7763d7da89
@ -9,11 +9,15 @@
|
|||||||
|
|
||||||
const int AlbumCoverFetcher::kMaxConcurrentRequests = 5;
|
const int AlbumCoverFetcher::kMaxConcurrentRequests = 5;
|
||||||
|
|
||||||
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent)
|
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent, QNetworkAccessManager* network)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
|
network_(network),
|
||||||
next_id_(0),
|
next_id_(0),
|
||||||
request_starter_(new QTimer(this))
|
request_starter_(new QTimer(this))
|
||||||
{
|
{
|
||||||
|
if (!network_.get()) {
|
||||||
|
network_.reset(new QNetworkAccessManager);
|
||||||
|
}
|
||||||
request_starter_->setInterval(1000);
|
request_starter_->setInterval(1000);
|
||||||
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
||||||
}
|
}
|
||||||
@ -68,7 +72,7 @@ void AlbumCoverFetcher::AlbumGetInfoFinished() {
|
|||||||
lastfm::XmlQuery query(lastfm::ws::parse(reply));
|
lastfm::XmlQuery query(lastfm::ws::parse(reply));
|
||||||
|
|
||||||
QUrl image_url(query["album"]["image size=large"].text());
|
QUrl image_url(query["album"]["image size=large"].text());
|
||||||
QNetworkReply* image_reply = network_.get(QNetworkRequest(image_url));
|
QNetworkReply* image_reply = network_->get(QNetworkRequest(image_url));
|
||||||
connect(image_reply, SIGNAL(finished()), SLOT(AlbumCoverFetchFinished()));
|
connect(image_reply, SIGNAL(finished()), SLOT(AlbumCoverFetchFinished()));
|
||||||
|
|
||||||
active_requests_[image_reply] = id;
|
active_requests_[image_reply] = id;
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <lastfm/Album>
|
#include <lastfm/Album>
|
||||||
|
|
||||||
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
|
||||||
class QNetworkReply;
|
class QNetworkReply;
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ class AlbumCoverFetcher : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AlbumCoverFetcher(QObject* parent = 0);
|
AlbumCoverFetcher(QObject* parent = 0, QNetworkAccessManager* network_ = 0);
|
||||||
virtual ~AlbumCoverFetcher() {}
|
virtual ~AlbumCoverFetcher() {}
|
||||||
|
|
||||||
static const int kMaxConcurrentRequests;
|
static const int kMaxConcurrentRequests;
|
||||||
@ -40,7 +42,7 @@ class AlbumCoverFetcher : public QObject {
|
|||||||
QString album;
|
QString album;
|
||||||
};
|
};
|
||||||
|
|
||||||
QNetworkAccessManager network_;
|
boost::scoped_ptr<QNetworkAccessManager> network_;
|
||||||
quint64 next_id_;
|
quint64 next_id_;
|
||||||
|
|
||||||
QQueue<QueuedRequest> queued_requests_;
|
QQueue<QueuedRequest> queued_requests_;
|
||||||
|
@ -29,6 +29,17 @@ set(GMOCK-SOURCES
|
|||||||
add_library(gmock ${GMOCK-SOURCES})
|
add_library(gmock ${GMOCK-SOURCES})
|
||||||
target_link_libraries(gmock gtest)
|
target_link_libraries(gmock gtest)
|
||||||
|
|
||||||
|
set(MOCK-SOURCES
|
||||||
|
mock_networkaccessmanager.cpp)
|
||||||
|
|
||||||
|
set(MOCK-MOC-HEADERS
|
||||||
|
mock_networkaccessmanager.h)
|
||||||
|
|
||||||
|
qt4_wrap_cpp(MOCK-SOURCES-MOC ${MOCK-MOC-HEADERS})
|
||||||
|
|
||||||
|
add_library(mocks ${MOCK-SOURCES} ${MOCK-SOURCES-MOC})
|
||||||
|
target_link_libraries(mocks gmock)
|
||||||
|
|
||||||
add_custom_target(test
|
add_custom_target(test
|
||||||
echo "Running tests"
|
echo "Running tests"
|
||||||
WORKING_DIRECTORY ${CURRENT_BINARY_DIR}
|
WORKING_DIRECTORY ${CURRENT_BINARY_DIR}
|
||||||
@ -41,7 +52,7 @@ macro(add_test_file test_source)
|
|||||||
${ARGV0}
|
${ARGV0}
|
||||||
main.cpp
|
main.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(${TEST_NAME} gmock clementine_lib)
|
target_link_libraries(${TEST_NAME} gmock clementine_lib mocks)
|
||||||
add_custom_command(TARGET test POST_BUILD
|
add_custom_command(TARGET test POST_BUILD
|
||||||
COMMAND ./${TEST_NAME})
|
COMMAND ./${TEST_NAME})
|
||||||
add_dependencies(test ${TEST_NAME})
|
add_dependencies(test ${TEST_NAME})
|
||||||
@ -51,3 +62,4 @@ endmacro (add_test_file)
|
|||||||
add_test_file(m3uparser_test.cpp)
|
add_test_file(m3uparser_test.cpp)
|
||||||
add_test_file(song_test.cpp)
|
add_test_file(song_test.cpp)
|
||||||
add_test_file(librarybackend_test.cpp)
|
add_test_file(librarybackend_test.cpp)
|
||||||
|
add_test_file(albumcoverfetcher_test.cpp)
|
||||||
|
59
tests/albumcoverfetcher_test.cpp
Normal file
59
tests/albumcoverfetcher_test.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "albumcoverfetcher.h"
|
||||||
|
|
||||||
|
#include <lastfm/ws.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QSignalSpy>
|
||||||
|
|
||||||
|
#include "mock_networkaccessmanager.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
int argc = 1;
|
||||||
|
char* argv[] = { "test", 0 };
|
||||||
|
|
||||||
|
class AlbumCoverFetcherTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
static void SetUpTestCase() {
|
||||||
|
lastfm::ws::ApiKey = "foobar";
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumCoverFetcherTest()
|
||||||
|
: app_(argc, (char**)argv) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUp() {
|
||||||
|
network_ = new MockNetworkAccessManager;
|
||||||
|
lastfm::setNetworkAccessManager(network_);
|
||||||
|
}
|
||||||
|
|
||||||
|
MockNetworkAccessManager* network_;
|
||||||
|
QCoreApplication app_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(AlbumCoverFetcherTest, FetchesAlbumCover) {
|
||||||
|
const char* data = "<lfm status=\"ok\"><album><name>Bar</name><artist>Foo</artist>"
|
||||||
|
"<image size=\"large\">http://example.com/image.jpg</image></album></lfm>";
|
||||||
|
|
||||||
|
QMap<QString, QString> params;
|
||||||
|
params["artist"] = "Foo";
|
||||||
|
params["album"] = "Bar";
|
||||||
|
params["api_key"] = "foobar";
|
||||||
|
MockNetworkReply* get_info_reply = network_->ExpectGet("audioscrobbler", params, 200, data);
|
||||||
|
params.clear();
|
||||||
|
MockNetworkReply* album_reply = network_->ExpectGet("http://example.com/image.jpg", params, 200, "");
|
||||||
|
|
||||||
|
AlbumCoverFetcher fetcher(NULL, network_);
|
||||||
|
QSignalSpy spy(&fetcher, SIGNAL(AlbumCoverFetched(quint64, const QImage&)));
|
||||||
|
ASSERT_TRUE(spy.isValid());
|
||||||
|
fetcher.FetchAlbumCover("Foo", "Bar");
|
||||||
|
|
||||||
|
get_info_reply->Done();
|
||||||
|
app_.processEvents(QEventLoop::AllEvents);
|
||||||
|
|
||||||
|
album_reply->Done();
|
||||||
|
app_.processEvents(QEventLoop::AllEvents);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, spy.count());
|
||||||
|
}
|
110
tests/mock_networkaccessmanager.cpp
Normal file
110
tests/mock_networkaccessmanager.cpp
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include "mock_networkaccessmanager.h"
|
||||||
|
|
||||||
|
#include <QtDebug>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
using std::min;
|
||||||
|
|
||||||
|
using ::testing::MakeMatcher;
|
||||||
|
using ::testing::Matcher;
|
||||||
|
using ::testing::MatcherInterface;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (QMap<QString, QString>::const_iterator it = expected_params_.begin();
|
||||||
|
it != expected_params_.end(); ++it) {
|
||||||
|
if (!url.hasQueryItem(it.key()) ||
|
||||||
|
url.queryItemValue(it.key()) != it.value()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 char* data) {
|
||||||
|
MockNetworkReply* reply = new MockNetworkReply(data);
|
||||||
|
reply->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, createRequest(
|
||||||
|
GetOperation, RequestForUrl(contains, expected_params), NULL)).
|
||||||
|
WillOnce(Return(reply));
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
MockNetworkAccessManager::~MockNetworkAccessManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
MockNetworkReply::MockNetworkReply()
|
||||||
|
: data_(NULL),
|
||||||
|
size_(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
MockNetworkReply::MockNetworkReply(const char* data)
|
||||||
|
: data_(data),
|
||||||
|
size_(strlen(data)),
|
||||||
|
pos_(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockNetworkReply::SetData(const char* data) {
|
||||||
|
data_ = data;
|
||||||
|
size_ = strlen(data);
|
||||||
|
pos_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 MockNetworkReply::readData(char* data, qint64 size) {
|
||||||
|
if (size_ == pos_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
qint64 bytes_to_read = min(size_ - pos_, size);
|
||||||
|
memcpy(data, data_, 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";
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockNetworkReply::Done() {
|
||||||
|
setOpenMode(QIODevice::ReadOnly);
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockNetworkReply::setAttribute(QNetworkRequest::Attribute code, const QVariant& value) {
|
||||||
|
QNetworkReply::setAttribute(code, value);
|
||||||
|
}
|
49
tests/mock_networkaccessmanager.h
Normal file
49
tests/mock_networkaccessmanager.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef MOCK_NETWORKACCESSAMANGER_H
|
||||||
|
#define MOCK_NETWORKACCESSMANAGER_H
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include "test_utils.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
class MockNetworkReply : public QNetworkReply {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MockNetworkReply();
|
||||||
|
MockNetworkReply(const char* data);
|
||||||
|
virtual ~MockNetworkReply() {}
|
||||||
|
|
||||||
|
void SetData(const char* data);
|
||||||
|
virtual void setAttribute(QNetworkRequest::Attribute code, const QVariant& value);
|
||||||
|
|
||||||
|
void Done();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MOCK_METHOD0(abort, void());
|
||||||
|
virtual qint64 readData(char* data, qint64);
|
||||||
|
virtual qint64 writeData(const char* data, qint64);
|
||||||
|
|
||||||
|
const char* data_;
|
||||||
|
qint64 size_;
|
||||||
|
qint64 pos_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MockNetworkAccessManager : public QNetworkAccessManager {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
virtual ~MockNetworkAccessManager();
|
||||||
|
MockNetworkReply* ExpectGet(
|
||||||
|
const QString& contains,
|
||||||
|
const QMap<QString, QString>& params,
|
||||||
|
int status,
|
||||||
|
const char* ret_data);
|
||||||
|
protected:
|
||||||
|
MOCK_METHOD3(createRequest, QNetworkReply*(Operation, const QNetworkRequest&, QIODevice*));
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,6 @@
|
|||||||
#include "test_utils.h"
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
#include <QNetworkRequest>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
@ -13,3 +14,7 @@ std::ostream& operator <<(std::ostream& stream, const QUrl& url) {
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator <<(std::ostream& stream, const QNetworkRequest& req) {
|
||||||
|
stream << req.url().toString().toStdString();
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
class QNetworkRequest;
|
||||||
class QString;
|
class QString;
|
||||||
class QUrl;
|
class QUrl;
|
||||||
|
|
||||||
std::ostream& operator <<(std::ostream& stream, const QString& str);
|
std::ostream& operator <<(std::ostream& stream, const QString& str);
|
||||||
std::ostream& operator <<(std::ostream& stream, const QUrl& url);
|
std::ostream& operator <<(std::ostream& stream, const QUrl& url);
|
||||||
|
std::ostream& operator <<(std::ostream& stream, const QNetworkRequest& req);
|
||||||
|
|
||||||
#endif // TEST_UTILS_H
|
#endif // TEST_UTILS_H
|
||||||
|
Loading…
Reference in New Issue
Block a user