Merge lp:~osomon/webbrowser-app/disable-favicon-provider-rtm into lp:webbrowser-app/rtm-14.09

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 776
Merged at revision: 775
Proposed branch: lp:~osomon/webbrowser-app/disable-favicon-provider-rtm
Merge into: lp:webbrowser-app/rtm-14.09
Diff against target: 1189 lines (+566/-443)
17 files modified
src/Ubuntu/Components/Extras/Browser/CMakeLists.txt (+2/-2)
src/Ubuntu/Web/CMakeLists.txt (+2/-2)
src/Ubuntu/Web/favicon-image-provider.cpp (+0/-125)
src/Ubuntu/Web/favicon-image-provider.h (+0/-47)
src/Ubuntu/Web/plugin.cpp (+0/-3)
src/app/CMakeLists.txt (+2/-1)
src/app/Favicon.qml (+9/-5)
src/app/browserapplication.cpp (+2/-0)
src/app/favicon-fetcher.cpp (+167/-0)
src/app/favicon-fetcher.h (+70/-0)
tests/unittests/CMakeLists.txt (+1/-1)
tests/unittests/favicon-fetcher/CMakeLists.txt (+10/-0)
tests/unittests/favicon-fetcher/tst_FaviconFetcherTests.cpp (+280/-0)
tests/unittests/favicon-image-provider/CMakeLists.txt (+0/-10)
tests/unittests/favicon-image-provider/tst_FaviconImageProviderTests.cpp (+0/-242)
tests/unittests/qml/CMakeLists.txt (+7/-2)
tests/unittests/qml/tst_QmlTests.cpp (+14/-3)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/disable-favicon-provider-rtm
Reviewer Review Type Date Requested Status
Bill Filler (community) Needs Fixing
Review via email: mp+242757@code.launchpad.net

Commit message

Replace the custom favicon image provider with a FaviconFetcher component that better handles cancelling pending requests.

To post a comment you must log in.
Revision history for this message
Bill Filler (bfiller) wrote :

we'll need to add an autopilot test (or qml test if that make sense) for this before it will be acceptable for rtm

review: Needs Fixing
776. By Olivier Tilloy

Replace the custom favicon image provider with a FaviconFetcher component that better handles cancelling pending requests.

Revision history for this message
Olivier Tilloy (osomon) wrote :

Following Florian’s suggestions, I replaced the custom favicon image provider with a FaviconFetcher component that better handles cancelling pending requests. It is fully unit-tested, including the use-case of emitting numerous queries in a row and ensuring that they are cancelled as a new one comes in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt'
2--- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-07-31 15:51:10 +0000
3+++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-11-27 10:18:45 +0000
4@@ -4,11 +4,11 @@
5
6 set(PLUGIN ubuntu-ui-extras-browser-plugin)
7
8-set(PLUGIN_SRC favicon-image-provider.cpp plugin.cpp)
9+set(PLUGIN_SRC plugin.cpp)
10
11 add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
12
13-qt5_use_modules(${PLUGIN} Core Gui Network Qml Quick)
14+qt5_use_modules(${PLUGIN} Core Gui Qml)
15
16 file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
17 install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR})
18
19=== modified file 'src/Ubuntu/Web/CMakeLists.txt'
20--- src/Ubuntu/Web/CMakeLists.txt 2014-07-31 15:51:10 +0000
21+++ src/Ubuntu/Web/CMakeLists.txt 2014-11-27 10:18:45 +0000
22@@ -4,11 +4,11 @@
23
24 set(PLUGIN ubuntu-web-plugin)
25
26-set(PLUGIN_SRC favicon-image-provider.cpp plugin.cpp)
27+set(PLUGIN_SRC plugin.cpp)
28
29 add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
30
31-qt5_use_modules(${PLUGIN} Core Gui Network Qml Quick)
32+qt5_use_modules(${PLUGIN} Core Gui Qml)
33
34 file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
35 install(TARGETS ${PLUGIN} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
36
37=== removed file 'src/Ubuntu/Web/favicon-image-provider.cpp'
38--- src/Ubuntu/Web/favicon-image-provider.cpp 2014-09-30 10:40:46 +0000
39+++ src/Ubuntu/Web/favicon-image-provider.cpp 1970-01-01 00:00:00 +0000
40@@ -1,125 +0,0 @@
41-/*
42- * Copyright 2014 Canonical Ltd.
43- *
44- * This file is part of webbrowser-app.
45- *
46- * webbrowser-app is free software; you can redistribute it and/or modify
47- * it under the terms of the GNU General Public License as published by
48- * the Free Software Foundation; version 3.
49- *
50- * webbrowser-app is distributed in the hope that it will be useful,
51- * but WITHOUT ANY WARRANTY; without even the implied warranty of
52- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53- * GNU General Public License for more details.
54- *
55- * You should have received a copy of the GNU General Public License
56- * along with this program. If not, see <http://www.gnu.org/licenses/>.
57- */
58-
59-#include "favicon-image-provider.h"
60-
61-// Qt
62-#include <QtCore/QCryptographicHash>
63-#include <QtCore/QDebug>
64-#include <QtCore/QDir>
65-#include <QtCore/QEventLoop>
66-#include <QtCore/QFileInfo>
67-#include <QtCore/QStandardPaths>
68-#include <QtCore/QUrl>
69-#include <QtNetwork/QNetworkAccessManager>
70-#include <QtNetwork/QNetworkReply>
71-#include <QtNetwork/QNetworkRequest>
72-
73-#define MAX_REDIRECTIONS 5
74-#define CACHE_EXPIRATION_DAYS 100
75-
76-FaviconImageProvider::FaviconImageProvider()
77- : QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading)
78-{
79- QDir cacheLocation(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/favicons");
80- m_cacheLocation = cacheLocation.absolutePath();
81- if (!cacheLocation.exists()) {
82- QDir::root().mkpath(m_cacheLocation);
83- }
84-}
85-
86-const QString& FaviconImageProvider::cacheLocation() const
87-{
88- return m_cacheLocation;
89-}
90-
91-QImage FaviconImageProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
92-{
93- if (id.isEmpty()) {
94- return QImage();
95- }
96-
97- QString extension;
98- int extensionIndex = id.lastIndexOf(".");
99- if (extensionIndex != -1) {
100- extension = id.mid(extensionIndex);
101- }
102- QString hash(QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex());
103- QString filepath = m_cacheLocation + "/" + hash + extension;
104-
105- QImage image;
106- QFileInfo fileinfo(filepath);
107- if (fileinfo.exists()) {
108- if (fileinfo.lastModified().daysTo(QDateTime::currentDateTime()) > CACHE_EXPIRATION_DAYS) {
109- image = downloadImage(id);
110- if (!image.isNull()) {
111- image.save(filepath);
112- }
113- } else {
114- image.load(filepath);
115- }
116- } else {
117- image = downloadImage(id);
118- if (!image.isNull()) {
119- image.save(filepath);
120- }
121- }
122-
123- if (!image.isNull()) {
124- *size = image.size();
125- }
126- if (!image.isNull() && requestedSize.isValid() && (image.size() != requestedSize)) {
127- return image.scaled(requestedSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
128- } else {
129- return image;
130- }
131-}
132-
133-QImage FaviconImageProvider::downloadImage(const QUrl& url)
134-{
135- if (!m_manager) {
136- m_manager.reset(new QNetworkAccessManager());
137- }
138- QUrl currentUrl(url);
139- int redirections = 0;
140- while (redirections < MAX_REDIRECTIONS) {
141- QNetworkRequest request(currentUrl);
142- request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
143- QEventLoop loop;
144- QObject::connect(m_manager.data(), SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()));
145- QNetworkReply* reply = m_manager->get(request);
146- loop.exec();
147- currentUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
148- if (currentUrl.isEmpty()) {
149- if (reply->error() != QNetworkReply::NoError) {
150- qWarning() << "Failed to download" << url << ":" << reply->errorString();
151- delete reply;
152- return QImage();
153- } else {
154- QByteArray data = reply->readAll();
155- delete reply;
156- return QImage::fromData(data);
157- }
158- } else {
159- delete reply;
160- ++redirections;
161- }
162- }
163- qWarning() << "Failed to download" << url << ": too many redirections";
164- return QImage();
165-}
166
167=== removed file 'src/Ubuntu/Web/favicon-image-provider.h'
168--- src/Ubuntu/Web/favicon-image-provider.h 2014-09-30 10:40:46 +0000
169+++ src/Ubuntu/Web/favicon-image-provider.h 1970-01-01 00:00:00 +0000
170@@ -1,47 +0,0 @@
171-/*
172- * Copyright 2014 Canonical Ltd.
173- *
174- * This file is part of webbrowser-app.
175- *
176- * webbrowser-app is free software; you can redistribute it and/or modify
177- * it under the terms of the GNU General Public License as published by
178- * the Free Software Foundation; version 3.
179- *
180- * webbrowser-app is distributed in the hope that it will be useful,
181- * but WITHOUT ANY WARRANTY; without even the implied warranty of
182- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
183- * GNU General Public License for more details.
184- *
185- * You should have received a copy of the GNU General Public License
186- * along with this program. If not, see <http://www.gnu.org/licenses/>.
187- */
188-
189-#ifndef __FAVICON_IMAGE_PROVIDER_H__
190-#define __FAVICON_IMAGE_PROVIDER_H__
191-
192-// Qt
193-#include <QtCore/QScopedPointer>
194-#include <QtCore/QString>
195-#include <QtCore/QtGlobal>
196-#include <QtQuick/QQuickImageProvider>
197-
198-class QNetworkAccessManager;
199-class QUrl;
200-
201-class FaviconImageProvider Q_DECL_FINAL : public QQuickImageProvider
202-{
203-public:
204- FaviconImageProvider();
205-
206- const QString& cacheLocation() const;
207-
208- QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize);
209-
210-private:
211- QImage downloadImage(const QUrl& url);
212-
213- QString m_cacheLocation;
214- QScopedPointer<QNetworkAccessManager> m_manager;
215-};
216-
217-#endif // __FAVICON_IMAGE_PROVIDER_H__
218
219=== modified file 'src/Ubuntu/Web/plugin.cpp'
220--- src/Ubuntu/Web/plugin.cpp 2014-10-06 14:12:48 +0000
221+++ src/Ubuntu/Web/plugin.cpp 2014-11-27 10:18:45 +0000
222@@ -17,7 +17,6 @@
223 */
224
225 #include "plugin.h"
226-#include "favicon-image-provider.h"
227
228 // Qt
229 #include <QtCore/QDir>
230@@ -115,8 +114,6 @@
231 context->setContextProperty("formFactor", getFormFactor());
232 context->setContextProperty("webviewDevtoolsDebugPort", getDevtoolsPort());
233 context->setContextProperty("webviewDevtoolsDebugHost", getDevtoolsHost());
234-
235- engine->addImageProvider("favicon", new FaviconImageProvider());
236 }
237
238 void UbuntuBrowserPlugin::registerTypes(const char* uri)
239
240=== modified file 'src/app/CMakeLists.txt'
241--- src/app/CMakeLists.txt 2014-08-06 13:57:06 +0000
242+++ src/app/CMakeLists.txt 2014-11-27 10:18:45 +0000
243@@ -9,13 +9,14 @@
244
245 set(COMMONLIB_SRC
246 browserapplication.cpp
247+ favicon-fetcher.cpp
248 session-storage.cpp
249 webbrowser-window.cpp
250 )
251
252 add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC})
253
254-qt5_use_modules(${COMMONLIB} Core Network Qml Quick Widgets)
255+qt5_use_modules(${COMMONLIB} Core Gui Network Qml Quick Widgets)
256
257 include_directories(${Qt5Quick_PRIVATE_INCLUDE_DIRS})
258
259
260=== modified file 'src/app/Favicon.qml'
261--- src/app/Favicon.qml 2014-09-26 13:29:30 +0000
262+++ src/app/Favicon.qml 2014-11-27 10:18:45 +0000
263@@ -18,9 +18,10 @@
264
265 import QtQuick 2.0
266 import Ubuntu.Components 1.1
267+import webbrowsercommon.private 0.1
268
269 Item {
270- property url source
271+ property alias source: fetcher.url
272 property bool fallbackIcon: true
273
274 width: units.dp(16)
275@@ -28,15 +29,18 @@
276
277 Image {
278 id: image
279- readonly property string url: parent.source.toString()
280- source: url ? "image://favicon/" + url : ""
281-
282+ source: fetcher.localUrl
283 anchors.fill: parent
284 }
285
286+ FaviconFetcher {
287+ id: fetcher
288+ }
289+
290 Icon {
291 anchors.fill: parent
292 name: "stock_website"
293- visible: parent.fallbackIcon && (image.status !== Image.Ready)
294+ visible: parent.fallbackIcon &&
295+ ((image.status !== Image.Ready) || !image.source.toString())
296 }
297 }
298
299=== modified file 'src/app/browserapplication.cpp'
300--- src/app/browserapplication.cpp 2014-10-02 20:47:10 +0000
301+++ src/app/browserapplication.cpp 2014-11-27 10:18:45 +0000
302@@ -35,6 +35,7 @@
303 // local
304 #include "browserapplication.h"
305 #include "config.h"
306+#include "favicon-fetcher.h"
307 #include "session-storage.h"
308 #include "webbrowser-window.h"
309
310@@ -143,6 +144,7 @@
311 }
312
313 const char* uri = "webbrowsercommon.private";
314+ qmlRegisterType<FaviconFetcher>(uri, 0, 1, "FaviconFetcher");
315 qmlRegisterType<SessionStorage>(uri, 0, 1, "SessionStorage");
316
317 m_engine = new QQmlEngine;
318
319=== added file 'src/app/favicon-fetcher.cpp'
320--- src/app/favicon-fetcher.cpp 1970-01-01 00:00:00 +0000
321+++ src/app/favicon-fetcher.cpp 2014-11-27 10:18:45 +0000
322@@ -0,0 +1,167 @@
323+/*
324+ * Copyright 2014 Canonical Ltd.
325+ *
326+ * This file is part of webbrowser-app.
327+ *
328+ * webbrowser-app is free software; you can redistribute it and/or modify
329+ * it under the terms of the GNU General Public License as published by
330+ * the Free Software Foundation; version 3.
331+ *
332+ * webbrowser-app is distributed in the hope that it will be useful,
333+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
334+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
335+ * GNU General Public License for more details.
336+ *
337+ * You should have received a copy of the GNU General Public License
338+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
339+ */
340+
341+#include "favicon-fetcher.h"
342+
343+// Qt
344+#include <QtCore/QCryptographicHash>
345+#include <QtCore/QDebug>
346+#include <QtCore/QDir>
347+#include <QtCore/QFileInfo>
348+#include <QtCore/QMetaObject>
349+#include <QtCore/QStandardPaths>
350+#include <QtGui/QImage>
351+#include <QtNetwork/QNetworkAccessManager>
352+#include <QtNetwork/QNetworkReply>
353+#include <QtNetwork/QNetworkRequest>
354+
355+#define MAX_REDIRECTIONS 5
356+#define CACHE_EXPIRATION_DAYS 100
357+
358+FaviconFetcher::FaviconFetcher(QObject* parent)
359+ : QObject(parent)
360+ , m_reply(0)
361+{
362+ QDir cacheLocation(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/favicons");
363+ m_cacheLocation = cacheLocation.absolutePath();
364+ if (!cacheLocation.exists()) {
365+ QDir::root().mkpath(m_cacheLocation);
366+ }
367+}
368+
369+FaviconFetcher::~FaviconFetcher()
370+{
371+ if (m_reply) {
372+ m_reply->abort();
373+ delete m_reply;
374+ }
375+}
376+
377+const QUrl& FaviconFetcher::url() const
378+{
379+ return m_url;
380+}
381+
382+void FaviconFetcher::setUrl(const QUrl& url)
383+{
384+ if (url != m_url) {
385+ m_url = url;
386+ Q_EMIT urlChanged();
387+
388+ setLocalUrl(QUrl());
389+
390+ if (m_reply) {
391+ m_reply->abort();
392+ m_reply = 0;
393+ }
394+
395+ if (!url.isValid()) {
396+ return;
397+ }
398+
399+ if (url.isLocalFile()) {
400+ setLocalUrl(url);
401+ return;
402+ }
403+
404+ QString id = url.toString(QUrl::None);
405+
406+ QString extension;
407+ int extensionIndex = id.lastIndexOf(".");
408+ if (extensionIndex != -1) {
409+ extension = id.mid(extensionIndex);
410+ }
411+
412+ QString hash(QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex());
413+ m_filepath = m_cacheLocation + "/" + hash + extension;
414+
415+ QFileInfo fileinfo(m_filepath);
416+ if (fileinfo.exists() && (fileinfo.lastModified().daysTo(QDateTime::currentDateTime()) < CACHE_EXPIRATION_DAYS)) {
417+ setLocalUrl(QUrl::fromLocalFile(m_filepath));
418+ } else {
419+ m_redirections = 0;
420+ download(url);
421+ }
422+ }
423+}
424+
425+const QUrl& FaviconFetcher::localUrl() const
426+{
427+ return m_localUrl;
428+}
429+
430+void FaviconFetcher::setLocalUrl(const QUrl& url)
431+{
432+ if (url != m_localUrl) {
433+ m_localUrl = url;
434+ Q_EMIT localUrlChanged();
435+ }
436+}
437+
438+const QString& FaviconFetcher::cacheLocation() const
439+{
440+ return m_cacheLocation;
441+}
442+
443+void FaviconFetcher::download(const QUrl& url)
444+{
445+ if (!m_manager) {
446+ m_manager.reset(new QNetworkAccessManager());
447+ connect(m_manager.data(), SIGNAL(finished(QNetworkReply*)),
448+ this, SLOT(downloadFinished(QNetworkReply*)));
449+ }
450+ QNetworkRequest request(url);
451+ request.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
452+ // For some reason slashdot.org closes the connection with the default
453+ // user agent string ("Mozilla/5.0"). Weird.
454+ request.setHeader(QNetworkRequest::UserAgentHeader, QString("Mozilla"));
455+ m_reply = m_manager->get(request);
456+}
457+
458+void FaviconFetcher::downloadFinished(QNetworkReply* reply)
459+{
460+ if (reply->error() == QNetworkReply::OperationCanceledError) {
461+ reply->deleteLater();
462+ return;
463+ }
464+ QUrl url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
465+ if (url.isEmpty()) {
466+ if (reply->error() == QNetworkReply::NoError) {
467+ QByteArray data = reply->readAll();
468+ if (QImage::fromData(data).save(m_filepath)) {
469+ setLocalUrl(QUrl::fromLocalFile(m_filepath));
470+ }
471+ } else {
472+ qWarning() << "Failed to download" << reply->url()
473+ << ":" << reply->errorString();
474+ }
475+ reply->deleteLater();
476+ m_reply = 0;
477+ } else {
478+ reply->deleteLater();
479+ m_reply = 0;
480+ if (++m_redirections < MAX_REDIRECTIONS) {
481+ QMetaObject::invokeMethod(this, "download",
482+ Qt::QueuedConnection,
483+ Q_ARG(QUrl, url));
484+ } else {
485+ qWarning() << "Failed to download" << m_url
486+ << ": too many redirections";
487+ }
488+ }
489+}
490
491=== added file 'src/app/favicon-fetcher.h'
492--- src/app/favicon-fetcher.h 1970-01-01 00:00:00 +0000
493+++ src/app/favicon-fetcher.h 2014-11-27 10:18:45 +0000
494@@ -0,0 +1,70 @@
495+/*
496+ * Copyright 2014 Canonical Ltd.
497+ *
498+ * This file is part of webbrowser-app.
499+ *
500+ * webbrowser-app is free software; you can redistribute it and/or modify
501+ * it under the terms of the GNU General Public License as published by
502+ * the Free Software Foundation; version 3.
503+ *
504+ * webbrowser-app is distributed in the hope that it will be useful,
505+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
506+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
507+ * GNU General Public License for more details.
508+ *
509+ * You should have received a copy of the GNU General Public License
510+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
511+ */
512+
513+#ifndef __FAVICON_FETCHER_H__
514+#define __FAVICON_FETCHER_H__
515+
516+// Qt
517+#include <QtCore/QScopedPointer>
518+#include <QtCore/QObject>
519+#include <QtCore/QString>
520+#include <QtCore/QtGlobal>
521+#include <QtCore/QUrl>
522+
523+class QNetworkAccessManager;
524+class QNetworkReply;
525+
526+class FaviconFetcher Q_DECL_FINAL : public QObject
527+{
528+ Q_OBJECT
529+
530+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
531+ Q_PROPERTY(QUrl localUrl READ localUrl NOTIFY localUrlChanged)
532+
533+public:
534+ FaviconFetcher(QObject* parent=0);
535+ ~FaviconFetcher();
536+
537+ const QUrl& url() const;
538+ void setUrl(const QUrl& url);
539+
540+ const QUrl& localUrl() const;
541+
542+ const QString& cacheLocation() const;
543+
544+Q_SIGNALS:
545+ void urlChanged() const;
546+ void localUrlChanged() const;
547+
548+private Q_SLOTS:
549+ void download(const QUrl& url);
550+ void downloadFinished(QNetworkReply* reply);
551+
552+private:
553+ void setLocalUrl(const QUrl& url);
554+
555+ QString m_cacheLocation;
556+ QScopedPointer<QNetworkAccessManager> m_manager;
557+ QNetworkReply* m_reply;
558+ QUrl m_url;
559+ QString m_filepath;
560+ int m_redirections;
561+ QUrl m_localUrl;
562+};
563+
564+#endif // __FAVICON_FETCHER_H__
565
566=== modified file 'tests/unittests/CMakeLists.txt'
567--- tests/unittests/CMakeLists.txt 2014-10-03 14:41:48 +0000
568+++ tests/unittests/CMakeLists.txt 2014-11-27 10:18:45 +0000
569@@ -15,4 +15,4 @@
570 add_subdirectory(cookie-store)
571 add_subdirectory(oxide-cookie-helper)
572 add_subdirectory(session-storage)
573-add_subdirectory(favicon-image-provider)
574+add_subdirectory(favicon-fetcher)
575
576=== added directory 'tests/unittests/favicon-fetcher'
577=== added file 'tests/unittests/favicon-fetcher/CMakeLists.txt'
578--- tests/unittests/favicon-fetcher/CMakeLists.txt 1970-01-01 00:00:00 +0000
579+++ tests/unittests/favicon-fetcher/CMakeLists.txt 2014-11-27 10:18:45 +0000
580@@ -0,0 +1,10 @@
581+set(TEST tst_FaviconFetcherTests)
582+set(SOURCES
583+ ${webbrowser-common_SOURCE_DIR}/favicon-fetcher.cpp
584+ tst_FaviconFetcherTests.cpp
585+)
586+add_executable(${TEST} ${SOURCES})
587+include_directories(${webbrowser-common_SOURCE_DIR})
588+qt5_use_modules(${TEST} Core Gui Network Test)
589+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
590+set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
591
592=== added file 'tests/unittests/favicon-fetcher/tst_FaviconFetcherTests.cpp'
593--- tests/unittests/favicon-fetcher/tst_FaviconFetcherTests.cpp 1970-01-01 00:00:00 +0000
594+++ tests/unittests/favicon-fetcher/tst_FaviconFetcherTests.cpp 2014-11-27 10:18:45 +0000
595@@ -0,0 +1,280 @@
596+/*
597+ * Copyright 2014 Canonical Ltd.
598+ *
599+ * This file is part of webbrowser-app.
600+ *
601+ * webbrowser-app is free software; you can redistribute it and/or modify
602+ * it under the terms of the GNU General Public License as published by
603+ * the Free Software Foundation; version 3.
604+ *
605+ * webbrowser-app is distributed in the hope that it will be useful,
606+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
607+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
608+ * GNU General Public License for more details.
609+ *
610+ * You should have received a copy of the GNU General Public License
611+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
612+ */
613+
614+// system
615+#include <utime.h>
616+
617+// Qt
618+#include <QtCore/QDateTime>
619+#include <QtCore/QDir>
620+#include <QtCore/QRegExp>
621+#include <QtCore/QString>
622+#include <QtCore/QStringList>
623+#include <QtCore/QTextStream>
624+#include <QtNetwork/QTcpServer>
625+#include <QtNetwork/QTcpSocket>
626+#include <QtTest/QSignalSpy>
627+#include <QtTest/QtTest>
628+
629+// local
630+#include "favicon-fetcher.h"
631+
632+const char icon_data[] = {
633+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x00,
634+ 0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
635+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
636+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
638+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
639+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
640+};
641+const int icon_data_size = 78;
642+
643+class TestHTTPServer : public QTcpServer
644+{
645+ Q_OBJECT
646+
647+public:
648+ TestHTTPServer(QObject* parent = 0)
649+ : QTcpServer(parent)
650+ {}
651+
652+ QString baseURL() const
653+ {
654+ return "http://" + serverAddress().toString() + ":" + QString::number(serverPort());
655+ }
656+
657+Q_SIGNALS:
658+ void gotRequest(const QString& path) const;
659+
660+protected:
661+ void incomingConnection(qintptr socketDescriptor)
662+ {
663+ QTcpSocket* socket = new QTcpSocket(this);
664+ connect(socket, SIGNAL(readyRead()), SLOT(readClient()));
665+ connect(socket, SIGNAL(disconnected()), SLOT(discardClient()));
666+ socket->setSocketDescriptor(socketDescriptor);
667+ }
668+
669+private Q_SLOTS:
670+ void readClient()
671+ {
672+ QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
673+ if (!socket) {
674+ return;
675+ }
676+ if (!socket->canReadLine()) {
677+ return;
678+ }
679+ QStringList tokens = QString(socket->readLine()).split(QRegExp("[ \r\n][ \r\n]*"));
680+ if (tokens.isEmpty()) {
681+ return;
682+ }
683+ if (tokens.first() != "GET") {
684+ return;
685+ }
686+ QString path = tokens[1];
687+ Q_EMIT gotRequest(path);
688+ QTextStream response(socket);
689+ response.setAutoDetectUnicode(true);
690+ QRegExp icon("/\\w+\\.ico");
691+ QRegExp redirection("^/redirect/(\\d+)/(.*)");
692+ if (icon.exactMatch(path)) {
693+ response << "HTTP/1.0 200 OK\r\n"
694+ << "Content-Length: " << icon_data_size << "\r\n"
695+ << "Content-Type: image/x-icon\r\n\r\n"
696+ << QString::fromLocal8Bit(icon_data, icon_data_size) << "\n";
697+ } else if (redirection.exactMatch(path)) {
698+ int n = redirection.cap(1).toInt();
699+ response << "HTTP/1.0 303 See Other\r\n"
700+ << "Content-Length: 9\r\n"
701+ << "Content-Type: text/plain\r\n"
702+ << "Location: " << baseURL();
703+ if (n == 1) {
704+ response << "/" << redirection.cap(2);
705+ } else {
706+ response << "/redirect/" << (n - 1) << "/" << redirection.cap(2);
707+ }
708+ response << "\r\n\r\n"
709+ << "see other\n";
710+ } else {
711+ response << "HTTP/1.0 404 Not Found\r\n"
712+ << "Content-Length: 9\r\n"
713+ << "Content-Type: text/plain\r\n\r\n"
714+ << "not found\n";
715+ }
716+ response.flush();
717+ socket->waitForBytesWritten();
718+ socket->disconnectFromHost();
719+ }
720+
721+ void discardClient()
722+ {
723+ QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
724+ if (socket) {
725+ socket->deleteLater();
726+ }
727+ }
728+};
729+
730+class FaviconFetcherTests : public QObject
731+{
732+ Q_OBJECT
733+
734+private:
735+ FaviconFetcher* fetcher;
736+ QSignalSpy* fetcherSpy;
737+ TestHTTPServer* server;
738+ QSignalSpy* serverSpy;
739+
740+private Q_SLOTS:
741+ void init()
742+ {
743+ {
744+ FaviconFetcher temp;
745+ QDir(temp.cacheLocation()).removeRecursively();
746+ }
747+ fetcher = new FaviconFetcher;
748+ fetcherSpy = new QSignalSpy(fetcher, SIGNAL(localUrlChanged()));
749+ server = new TestHTTPServer;
750+ server->listen();
751+ serverSpy = new QSignalSpy(server, SIGNAL(gotRequest(const QString&)));
752+ }
753+
754+ void cleanup()
755+ {
756+ delete serverSpy;
757+ delete server;
758+ delete fetcherSpy;
759+ delete fetcher;
760+ }
761+
762+ void shouldCacheIcon()
763+ {
764+ QUrl url(server->baseURL() + "/favicon1.ico");
765+ fetcher->setUrl(url);
766+ QCOMPARE(fetcher->url(), url);
767+ QVERIFY(fetcherSpy->wait());
768+ QCOMPARE(serverSpy->count(), 1);
769+ QString cached = fetcher->localUrl().path();
770+ QVERIFY(cached.startsWith(fetcher->cacheLocation()));
771+ QVERIFY(QFileInfo::exists(cached));
772+ }
773+
774+ void shouldNotCacheLocalIcon()
775+ {
776+ QUrl url("file:///tmp/favicon.ico");
777+ fetcher->setUrl(url);
778+ QCOMPARE(fetcherSpy->count(), 1);
779+ QVERIFY(serverSpy->isEmpty());
780+ QCOMPARE(fetcher->localUrl(), url);
781+ QDir cache(fetcher->cacheLocation(), "", QDir::Unsorted, QDir::Files | QDir::NoDotAndDotDot);
782+ QCOMPARE(cache.count(), (uint) 0);
783+ }
784+
785+ void shouldNotCacheInvalidIcon()
786+ {
787+ // First fetch a valid icon to ensure localUrl is initially not empty
788+ QUrl url(server->baseURL() + "/favicon1.ico");
789+ fetcher->setUrl(url);
790+ QVERIFY(fetcherSpy->wait());
791+ QVERIFY(!fetcher->localUrl().isEmpty());
792+ // Then request an invalid one
793+ url = QUrl(server->baseURL() + "/invalid");
794+ fetcher->setUrl(url);
795+ QVERIFY(serverSpy->wait());
796+ QVERIFY(fetcher->localUrl().isEmpty());
797+ }
798+
799+ void shouldReturnCachedIcon()
800+ {
801+ // First fetch an icon so that it’s cached
802+ QUrl url(server->baseURL() + "/favicon1.ico");
803+ fetcher->setUrl(url);
804+ QVERIFY(fetcherSpy->wait());
805+ QUrl localUrl = fetcher->localUrl();
806+ QVERIFY(!localUrl.isEmpty());
807+ // Then fetch another icon
808+ fetcher->setUrl(QUrl(server->baseURL() + "/favicon2.ico"));
809+ QVERIFY(fetcherSpy->wait());
810+ QVERIFY(!fetcher->localUrl().isEmpty());
811+ // Then fetch the first icon again, and verify it comes from the cache
812+ serverSpy->clear();
813+ fetcher->setUrl(url);
814+ QCOMPARE(fetcher->localUrl(), localUrl);
815+ QVERIFY(serverSpy->isEmpty());
816+ }
817+
818+ void shouldHandleRedirections()
819+ {
820+ QUrl url(server->baseURL() + "/redirect/3/favicon1.ico");
821+ fetcher->setUrl(url);
822+ QVERIFY(fetcherSpy->wait());
823+ QCOMPARE(serverSpy->count(), 4);
824+ }
825+
826+ void shouldNotHandleTooManyRedirections()
827+ {
828+ QUrl url(server->baseURL() + "/redirect/8/favicon1.ico");
829+ fetcher->setUrl(url);
830+ for (int i = 0; i < 5; ++i)
831+ QVERIFY(!fetcherSpy->wait(500));
832+ QCOMPARE(serverSpy->count(), 5);
833+ }
834+
835+ void shouldDiscardOldCachedIcons()
836+ {
837+ // First fetch an icon, and touch the cached file on disk to ensure
838+ // it will be considered out of date next time it’s requested
839+ QUrl url(server->baseURL() + "/favicon1.ico");
840+ fetcher->setUrl(url);
841+ QVERIFY(fetcherSpy->wait());
842+ QUrl localUrl = fetcher->localUrl();
843+ struct utimbuf ubuf;
844+ ubuf.modtime = QDateTime::currentDateTime().addYears(-1).toTime_t();
845+ QCOMPARE(utime(localUrl.path().toUtf8().constData(), &ubuf), 0);
846+ // Then fetch another icon
847+ fetcher->setUrl(QUrl(server->baseURL() + "/favicon2.ico"));
848+ QVERIFY(fetcherSpy->wait());
849+ QVERIFY(!fetcher->localUrl().isEmpty());
850+ // Then fetch the first icon again, and verify it is being re-downloaded
851+ serverSpy->clear();
852+ fetcher->setUrl(url);
853+ QVERIFY(fetcherSpy->wait());
854+ QCOMPARE(fetcher->localUrl(), localUrl);
855+ QCOMPARE(serverSpy->count(), 1);
856+ }
857+
858+ void shouldCancelRequests()
859+ {
860+ // Issue several requests rapidly in succession, and verify that
861+ // all the previous ones are discarded
862+ for (int i = 1; i < 10; ++i) {
863+ QUrl url(server->baseURL() + "/favicon" + QString::number(i) + ".ico");
864+ fetcher->setUrl(url);
865+ QVERIFY(serverSpy->wait());
866+ }
867+ QVERIFY(fetcherSpy->wait());
868+ QCOMPARE(serverSpy->count(), 9);
869+ QCOMPARE(fetcherSpy->count(), 1);
870+ }
871+};
872+
873+QTEST_MAIN(FaviconFetcherTests)
874+
875+#include "tst_FaviconFetcherTests.moc"
876
877=== removed directory 'tests/unittests/favicon-image-provider'
878=== removed file 'tests/unittests/favicon-image-provider/CMakeLists.txt'
879--- tests/unittests/favicon-image-provider/CMakeLists.txt 2014-09-30 11:52:33 +0000
880+++ tests/unittests/favicon-image-provider/CMakeLists.txt 1970-01-01 00:00:00 +0000
881@@ -1,10 +0,0 @@
882-set(TEST tst_FaviconImageProviderTests)
883-set(SOURCES
884- ${ubuntu-web-plugin_SOURCE_DIR}/favicon-image-provider.cpp
885- tst_FaviconImageProviderTests.cpp
886-)
887-add_executable(${TEST} ${SOURCES})
888-include_directories(${ubuntu-web-plugin_SOURCE_DIR})
889-qt5_use_modules(${TEST} Core Quick Network Test)
890-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
891-set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
892
893=== removed file 'tests/unittests/favicon-image-provider/tst_FaviconImageProviderTests.cpp'
894--- tests/unittests/favicon-image-provider/tst_FaviconImageProviderTests.cpp 2014-09-30 10:40:46 +0000
895+++ tests/unittests/favicon-image-provider/tst_FaviconImageProviderTests.cpp 1970-01-01 00:00:00 +0000
896@@ -1,242 +0,0 @@
897-/*
898- * Copyright 2014 Canonical Ltd.
899- *
900- * This file is part of webbrowser-app.
901- *
902- * webbrowser-app is free software; you can redistribute it and/or modify
903- * it under the terms of the GNU General Public License as published by
904- * the Free Software Foundation; version 3.
905- *
906- * webbrowser-app is distributed in the hope that it will be useful,
907- * but WITHOUT ANY WARRANTY; without even the implied warranty of
908- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
909- * GNU General Public License for more details.
910- *
911- * You should have received a copy of the GNU General Public License
912- * along with this program. If not, see <http://www.gnu.org/licenses/>.
913- */
914-
915-// system
916-#include <utime.h>
917-
918-// Qt
919-#include <QtCore/QDateTime>
920-#include <QtCore/QDir>
921-#include <QtCore/QRegExp>
922-#include <QtCore/QString>
923-#include <QtCore/QTextStream>
924-#include <QtNetwork/QNetworkAccessManager>
925-#include <QtNetwork/QTcpServer>
926-#include <QtTest/QtTest>
927-
928-// local
929-#include "favicon-image-provider.h"
930-
931-const char icon_data[] = {
932- 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x00,
933- 0x01, 0x00, 0x38, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00,
934- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
935- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
936- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
937- 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
938- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
939-};
940-const int icon_data_size = 78;
941-
942-class TestHTTPServer : public QTcpServer
943-{
944- Q_OBJECT
945-
946-public:
947- QStringList requests;
948-
949- TestHTTPServer(QObject* parent = 0)
950- : QTcpServer(parent)
951- {}
952-
953- QString baseURL() const
954- {
955- return "http://" + serverAddress().toString() + ":" + QString::number(serverPort());
956- }
957-
958-protected:
959- void incomingConnection(qintptr socketDescriptor)
960- {
961- QTcpSocket* socket = new QTcpSocket(this);
962- connect(socket, SIGNAL(readyRead()), SLOT(readClient()));
963- connect(socket, SIGNAL(disconnected()), SLOT(discardClient()));
964- socket->setSocketDescriptor(socketDescriptor);
965- }
966-
967-private Q_SLOTS:
968- void readClient()
969- {
970- QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
971- if (!socket) {
972- return;
973- }
974- if (!socket->canReadLine()) {
975- return;
976- }
977- QStringList tokens = QString(socket->readLine()).split(QRegExp("[ \r\n][ \r\n]*"));
978- if (tokens.isEmpty()) {
979- return;
980- }
981- if (tokens.first() != "GET") {
982- return;
983- }
984- QString path = tokens[1];
985- requests << path;
986- QTextStream response(socket);
987- response.setAutoDetectUnicode(true);
988- QRegExp icon("/\\w+\\.ico");
989- QRegExp redirection("^/redirect/(\\d+)/(.*)");
990- if (icon.exactMatch(path)) {
991- response << "HTTP/1.0 200 OK\r\n"
992- << "Content-Length: " << icon_data_size << "\r\n"
993- << "Content-Type: image/x-icon\r\n\r\n"
994- << QString::fromLocal8Bit(icon_data, icon_data_size) << "\n";
995- } else if (path == "/invalid") {
996- response << "HTTP/1.0 404 Not Found\r\n"
997- << "Content-Length: 9\r\n"
998- << "Content-Type: text/plain\r\n\r\n"
999- << "not found\n";
1000- } else if (redirection.exactMatch(path)) {
1001- int n = redirection.cap(1).toInt();
1002- response << "HTTP/1.0 303 See Other\r\n"
1003- << "Content-Length: 9\r\n"
1004- << "Content-Type: text/plain\r\n"
1005- << "Location: " << baseURL();
1006- if (n == 1) {
1007- response << "/" << redirection.cap(2);
1008- } else {
1009- response << "/redirect/" << (n - 1) << "/" << redirection.cap(2);
1010- }
1011- response << "\r\n\r\n"
1012- << "see other\n";
1013- }
1014- socket->close();
1015- }
1016-
1017- void discardClient()
1018- {
1019- QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
1020- if (socket) {
1021- socket->deleteLater();
1022- }
1023- }
1024-};
1025-
1026-class FaviconImageProviderTests : public QObject
1027-{
1028- Q_OBJECT
1029-
1030-private:
1031- FaviconImageProvider* provider;
1032- TestHTTPServer* server;
1033-
1034-private Q_SLOTS:
1035- void init()
1036- {
1037- {
1038- FaviconImageProvider temp;
1039- QDir(temp.cacheLocation()).removeRecursively();
1040- }
1041- provider = new FaviconImageProvider;
1042- server = new TestHTTPServer;
1043- server->listen();
1044- }
1045-
1046- void cleanup()
1047- {
1048- delete server;
1049- delete provider;
1050- }
1051-
1052- void shouldDiscardEmptyRequests()
1053- {
1054- QSize size;
1055- QImage icon = provider->requestImage("", &size, QSize());
1056- QVERIFY(icon.isNull());
1057- QVERIFY(!size.isValid());
1058- }
1059-
1060- void shouldFetchIcon()
1061- {
1062- QSize size;
1063- QImage icon = provider->requestImage(server->baseURL() + "/favicon1.ico", &size, QSize());
1064- QVERIFY(!icon.isNull());
1065- QCOMPARE(icon.size(), QSize(1, 1));
1066- QCOMPARE(size, QSize(1, 1));
1067- QCOMPARE(server->requests.size(), 1);
1068- }
1069-
1070- void shouldNotFetchInvalidIcon()
1071- {
1072- QSize size;
1073- QImage icon = provider->requestImage(server->baseURL() + "/invalid", &size, QSize());
1074- QVERIFY(icon.isNull());
1075- QVERIFY(!size.isValid());
1076- QCOMPARE(server->requests.size(), 1);
1077- }
1078-
1079- void shouldReturnCachedIcon()
1080- {
1081- QSize size;
1082- QImage icon = provider->requestImage(server->baseURL() + "/favicon2.ico", &size, QSize());
1083- QVERIFY(!icon.isNull());
1084- QCOMPARE(server->requests.size(), 1);
1085- server->requests.clear();
1086- QImage icon2 = provider->requestImage(server->baseURL() + "/favicon2.ico", &size, QSize());
1087- QVERIFY(!icon2.isNull());
1088- QVERIFY(server->requests.isEmpty());
1089- }
1090-
1091- void shouldHandleRedirections()
1092- {
1093- QSize size;
1094- QImage icon = provider->requestImage(server->baseURL() + "/redirect/3/favicon3.ico", &size, QSize());
1095- QVERIFY(!icon.isNull());
1096- QCOMPARE(icon.size(), QSize(1, 1));
1097- QCOMPARE(size, QSize(1, 1));
1098- QCOMPARE(server->requests.size(), 4);
1099- }
1100-
1101- void shouldNotHandleTooManyRedirections()
1102- {
1103- QSize size;
1104- QImage icon = provider->requestImage(server->baseURL() + "/redirect/8/favicon4.ico", &size, QSize());
1105- QVERIFY(icon.isNull());
1106- QVERIFY(!size.isValid());
1107- QCOMPARE(server->requests.size(), 5);
1108- }
1109-
1110- void shouldScaleIcon()
1111- {
1112- QSize size;
1113- QImage icon = provider->requestImage(server->baseURL() + "/favicon5.ico", &size, QSize(3, 3));
1114- QVERIFY(!icon.isNull());
1115- QCOMPARE(icon.size(), QSize(3, 3));
1116- QCOMPARE(size, QSize(1, 1));
1117- }
1118-
1119- void shouldDiscardOldCachedIcons()
1120- {
1121- QSize size;
1122- QImage icon = provider->requestImage(server->baseURL() + "/favicon6.ico", &size, QSize());
1123- QVERIFY(!icon.isNull());
1124- server->requests.clear();
1125- QDir cache(provider->cacheLocation(), "", QDir::Unsorted, QDir::Files | QDir::NoDotAndDotDot);
1126- QCOMPARE(cache.count(), (uint) 1);
1127- QString filepath = cache.filePath(cache[0]);
1128- struct utimbuf ubuf;
1129- ubuf.modtime = QDateTime::currentDateTime().addYears(-1).toTime_t();
1130- QCOMPARE(utime(filepath.toUtf8().constData(), &ubuf), 0);
1131- icon = provider->requestImage(server->baseURL() + "/favicon6.ico", &size, QSize());
1132- QVERIFY(!icon.isNull());
1133- QCOMPARE(server->requests.size(), 1);
1134- }
1135-};
1136-
1137-QTEST_MAIN(FaviconImageProviderTests)
1138-#include "tst_FaviconImageProviderTests.moc"
1139
1140=== modified file 'tests/unittests/qml/CMakeLists.txt'
1141--- tests/unittests/qml/CMakeLists.txt 2014-08-22 13:49:15 +0000
1142+++ tests/unittests/qml/CMakeLists.txt 2014-11-27 10:18:45 +0000
1143@@ -7,8 +7,13 @@
1144 endif()
1145
1146 set(TEST tst_QmlTests)
1147-add_executable(${TEST} tst_QmlTests.cpp)
1148-qt5_use_modules(${TEST} QuickTest)
1149+set(SOURCES
1150+ ${webbrowser-common_SOURCE_DIR}/favicon-fetcher.cpp
1151+ tst_QmlTests.cpp
1152+)
1153+add_executable(${TEST} ${SOURCES})
1154+qt5_use_modules(${TEST} Qml QuickTest)
1155+include_directories(${webbrowser-common_SOURCE_DIR})
1156 add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -import ${CMAKE_BINARY_DIR}/src)
1157
1158 # copy qml files under test to build dir
1159
1160=== modified file 'tests/unittests/qml/tst_QmlTests.cpp'
1161--- tests/unittests/qml/tst_QmlTests.cpp 2014-08-22 13:49:15 +0000
1162+++ tests/unittests/qml/tst_QmlTests.cpp 2014-11-27 10:18:45 +0000
1163@@ -1,5 +1,5 @@
1164 /*
1165- * Copyright 2013 Canonical Ltd.
1166+ * Copyright 2013-2014 Canonical Ltd.
1167 *
1168 * This file is part of webbrowser-app.
1169 *
1170@@ -16,6 +16,17 @@
1171 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1172 */
1173
1174+// Qt
1175+#include <QtQml/QtQml>
1176 #include <QtQuickTest/QtQuickTest>
1177-QUICK_TEST_MAIN(QmlTests)
1178-
1179+
1180+// local
1181+#include "favicon-fetcher.h"
1182+
1183+int main(int argc, char** argv)
1184+{
1185+ const char* uri = "webbrowsercommon.private";
1186+ qmlRegisterType<FaviconFetcher>(uri, 0, 1, "FaviconFetcher");
1187+
1188+ return quick_test_main(argc, argv, "QmlTests", 0);
1189+}

Subscribers

People subscribed via source and target branches