mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-18 20:34:39 +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;
|
||||
|
||||
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent)
|
||||
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent, QNetworkAccessManager* network)
|
||||
: QObject(parent),
|
||||
network_(network),
|
||||
next_id_(0),
|
||||
request_starter_(new QTimer(this))
|
||||
{
|
||||
if (!network_.get()) {
|
||||
network_.reset(new QNetworkAccessManager);
|
||||
}
|
||||
request_starter_->setInterval(1000);
|
||||
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
||||
}
|
||||
@ -68,7 +72,7 @@ void AlbumCoverFetcher::AlbumGetInfoFinished() {
|
||||
lastfm::XmlQuery query(lastfm::ws::parse(reply));
|
||||
|
||||
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()));
|
||||
|
||||
active_requests_[image_reply] = id;
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#include <lastfm/Album>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
class QNetworkReply;
|
||||
class QString;
|
||||
|
||||
@ -16,7 +18,7 @@ class AlbumCoverFetcher : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AlbumCoverFetcher(QObject* parent = 0);
|
||||
AlbumCoverFetcher(QObject* parent = 0, QNetworkAccessManager* network_ = 0);
|
||||
virtual ~AlbumCoverFetcher() {}
|
||||
|
||||
static const int kMaxConcurrentRequests;
|
||||
@ -40,7 +42,7 @@ class AlbumCoverFetcher : public QObject {
|
||||
QString album;
|
||||
};
|
||||
|
||||
QNetworkAccessManager network_;
|
||||
boost::scoped_ptr<QNetworkAccessManager> network_;
|
||||
quint64 next_id_;
|
||||
|
||||
QQueue<QueuedRequest> queued_requests_;
|
||||
|
@ -29,6 +29,17 @@ set(GMOCK-SOURCES
|
||||
add_library(gmock ${GMOCK-SOURCES})
|
||||
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
|
||||
echo "Running tests"
|
||||
WORKING_DIRECTORY ${CURRENT_BINARY_DIR}
|
||||
@ -41,7 +52,7 @@ macro(add_test_file test_source)
|
||||
${ARGV0}
|
||||
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
|
||||
COMMAND ./${TEST_NAME})
|
||||
add_dependencies(test ${TEST_NAME})
|
||||
@ -51,3 +62,4 @@ endmacro (add_test_file)
|
||||
add_test_file(m3uparser_test.cpp)
|
||||
add_test_file(song_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 <QNetworkRequest>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
@ -13,3 +14,7 @@ std::ostream& operator <<(std::ostream& stream, const QUrl& url) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::ostream& operator <<(std::ostream& stream, const QNetworkRequest& req) {
|
||||
stream << req.url().toString().toStdString();
|
||||
return stream;
|
||||
}
|
||||
|
@ -3,10 +3,12 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class QNetworkRequest;
|
||||
class QString;
|
||||
class QUrl;
|
||||
|
||||
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 QNetworkRequest& req);
|
||||
|
||||
#endif // TEST_UTILS_H
|
||||
|
Loading…
Reference in New Issue
Block a user