From c164a53bacb875bf8a04bf834c8879a81c6748b4 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sat, 7 Aug 2021 21:28:15 +0200 Subject: [PATCH 01/10] cpp based UrlUtils (instead of UrlUtils.js), with unit tests --- clickable.json | 2 +- src/app/CMakeLists.txt | 3 + src/app/DomainPermissionsPage.qml | 1 - src/app/DomainSettingsPage.qml | 1 - src/app/DownloadsPage.qml | 1 - src/app/UrlUtils.js | 144 ------------------ src/app/WebViewImpl.qml | 1 - src/app/ZoomControls.qml | 1 - src/app/browserapplication.cpp | 3 + src/app/url-utils.cpp | 126 +++++++++++++++ src/app/url-utils.h | 78 ++++++++++ src/app/webbrowser/AddressBar.qml | 2 +- src/app/webbrowser/Browser.qml | 1 - src/app/webbrowser/SettingsPage.qml | 2 +- src/app/webbrowser/TabComponent.qml | 2 +- src/app/webcontainer/WebViewImplOxide.qml | 1 - .../webcontainer/WebappContainerWebview.qml | 2 +- tests/unittests/CMakeLists.txt | 2 +- tests/unittests/url-utils/CMakeLists.txt | 13 ++ .../unittests/url-utils/tst_UrlUtilsTests.cpp | 134 ++++++++++++++++ 20 files changed, 363 insertions(+), 157 deletions(-) delete mode 100644 src/app/UrlUtils.js create mode 100644 src/app/url-utils.cpp create mode 100644 src/app/url-utils.h create mode 100644 tests/unittests/url-utils/CMakeLists.txt create mode 100644 tests/unittests/url-utils/tst_UrlUtilsTests.cpp diff --git a/clickable.json b/clickable.json index d6104b3d1..e0e6edde3 100644 --- a/clickable.json +++ b/clickable.json @@ -1,5 +1,5 @@ { - "template": "cmake", + "builder": "cmake", "kill": "morph-browser", "build_args": "-DCLICK_MODE=ON", "dependencies_target": [ diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index a6ac241e1..8402776ef 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -5,6 +5,7 @@ find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5Qml REQUIRED) find_package(Qt5Quick REQUIRED) +find_package(Qt5Sql REQUIRED) find_package(Qt5Widgets REQUIRED) #find_package(Qt5WebEngine REQUIRED) @@ -33,6 +34,7 @@ set(COMMONLIB_SRC mime-database.cpp session-storage.cpp single-instance-manager.cpp + url-utils.cpp ) add_library(${COMMONLIB} STATIC ${COMMONLIB_SRC}) @@ -44,6 +46,7 @@ target_link_libraries(${COMMONLIB} Qt5::Network Qt5::Qml Qt5::Quick + Qt5::Sql Qt5::Widgets Qt5WebEngine Qt5WebEngineCore diff --git a/src/app/DomainPermissionsPage.qml b/src/app/DomainPermissionsPage.qml index a883a600a..0233d1d92 100644 --- a/src/app/DomainPermissionsPage.qml +++ b/src/app/DomainPermissionsPage.qml @@ -24,7 +24,6 @@ import Ubuntu.Components 1.3 import Ubuntu.Components.Popups 1.3 import Ubuntu.Content 1.3 import webbrowsercommon.private 0.1 -import "UrlUtils.js" as UrlUtils FocusScope { id: domainPermissionsItem diff --git a/src/app/DomainSettingsPage.qml b/src/app/DomainSettingsPage.qml index a19c33c9e..1506b2f28 100644 --- a/src/app/DomainSettingsPage.qml +++ b/src/app/DomainSettingsPage.qml @@ -23,7 +23,6 @@ import Ubuntu.Components 1.3 import Ubuntu.Components.Popups 1.3 import Ubuntu.Content 1.3 import webbrowsercommon.private 0.1 -import "UrlUtils.js" as UrlUtils FocusScope { id: domainSettingsItem diff --git a/src/app/DownloadsPage.qml b/src/app/DownloadsPage.qml index 20875e22c..b749bbd9a 100644 --- a/src/app/DownloadsPage.qml +++ b/src/app/DownloadsPage.qml @@ -24,7 +24,6 @@ import Ubuntu.Content 1.3 import webbrowsercommon.private 0.1 import "MimeTypeMapper.js" as MimeTypeMapper -import "UrlUtils.js" as UrlUtils import "FileUtils.js" as FileUtils BrowserPage { diff --git a/src/app/UrlUtils.js b/src/app/UrlUtils.js deleted file mode 100644 index c3d48b786..000000000 --- a/src/app/UrlUtils.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2014 Canonical Ltd. - * - * This file is part of morph-browser. - * - * morph-browser 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; version 3. - * - * morph-browser 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 this program. If not, see . -*/ -/*jslint node: true */ -'use strict'; - -function extractScheme(url) { - var urlString = url.toString(); - return urlString.substring(0,urlString.indexOf(":")); -} - -function removeScheme(url) { - var rest = url.toString(); - var indexOfScheme = rest.indexOf(":"); - if (indexOfScheme !== -1) { - rest = rest.slice(indexOfScheme + 1); - - if (rest.indexOf("//") === 0) - { - rest = rest.slice(2); - } - } - return rest; -} - -function schemeIs(url, expectedScheme) { - return (extractScheme(url) === expectedScheme); -} - -function hasCustomScheme(url) { - - switch (extractScheme(url)) { - case 'chrome-extension': - case 'http': - case 'https': - case 'file': - case 'ftp': - case 'data': - case 'mailto': - return false; - default: - return true; - } -} - -function extractAuthority(url) { - var authority = removeScheme(url); - var indexOfPath = authority.indexOf("/"); - if (indexOfPath !== -1) { - authority = authority.slice(0, indexOfPath); - } - return authority; -} - -function extractHost(url) { - var host = extractAuthority(url); - var indexOfAt = host.indexOf("@"); - if (indexOfAt !== -1) { - host = host.slice(indexOfAt + 1); - } - var indexOfColon = host.indexOf(":"); - if (indexOfColon !== -1) { - host = host.slice(0, indexOfColon); - } - return host; -} - -function hostIs(url, expectedHost) { - return (extractHost(url) === expectedHost); -} - -function fixUrl(address) { - var url = address; - if (address.toLowerCase() === "about:blank") { - return address.toLowerCase(); - } else if (address.match(/^data:/i)) { - return "data:" + address.substr(5); - } else if (address.substr(0, 1) === "/") { - url = "file://" + address; - } else if (address.indexOf("://") === -1) { - url = "http://" + address; - } - return url; -} - -function looksLikeAUrl(address) { - if (address.match(/^data:/i)) { - return true; - } - if (address.match(/^file:/i)) { - return true; - } - if (address.match(/^view-source:/i)) { - return true; - } - if (address.match(/^chrome-extension:/i)) { - return true; - } - var terms = address.split(/\s/); - if (terms.length > 1) { - return false; - } - if (address.toLowerCase() === "about:blank") { - return true; - } - if (address.substr(0, 1) === "/") { - return true; - } - if (address.match(/^https?:\/\//i) || - address.match(/^file:\/\//i) || - address.match(/^[a-z]+:\/\//i)) { - return true; - } - if (address.split('/', 1)[0].match(/\.[a-zA-Z]{2,}$/)) { - return true; - } - if (address.split('/', 1)[0].match(/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}/)) { - return true; - } - return false; -} - -// special extension urls -function getPdfViewerExtensionUrlPrefix() { - return "chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/index.html?"; -} - -function isPdfViewerExtensionUrl(url) { - return (url.toString().indexOf(getPdfViewerExtensionUrlPrefix()) === 0); -} diff --git a/src/app/WebViewImpl.qml b/src/app/WebViewImpl.qml index c49a47009..5999bdef6 100644 --- a/src/app/WebViewImpl.qml +++ b/src/app/WebViewImpl.qml @@ -24,7 +24,6 @@ import QtWebEngine 1.10 import Morph.Web 0.1 import webbrowsercommon.private 0.1 import "actions" as Actions -import "UrlUtils.js" as UrlUtils WebView { id: webview diff --git a/src/app/ZoomControls.qml b/src/app/ZoomControls.qml index c666c450b..bdadbc72b 100644 --- a/src/app/ZoomControls.qml +++ b/src/app/ZoomControls.qml @@ -3,7 +3,6 @@ import Ubuntu.Components 1.3 // For UbuntuShape. import Ubuntu.Components.Popups 1.3 as Popups // For saveDialog. import QtWebEngine 1.7 import webbrowsercommon.private 0.1 // For DomainSettingsModel singleton. -import "UrlUtils.js" as UrlUtils // ZoomControls object to provide zoom menu, control and autofit logic for WebViewImpl. // Scope requirements: diff --git a/src/app/browserapplication.cpp b/src/app/browserapplication.cpp index 8085b9441..33ef81ea6 100644 --- a/src/app/browserapplication.cpp +++ b/src/app/browserapplication.cpp @@ -47,6 +47,7 @@ #include "meminfo.h" #include "mime-database.h" #include "session-storage.h" +#include "url-utils.h" BrowserApplication::BrowserApplication(int& argc, char** argv) : QApplication(argc, argv) @@ -108,6 +109,7 @@ MAKE_SINGLETON_FACTORY(DownloadsModel) MAKE_SINGLETON_FACTORY(FileOperations) MAKE_SINGLETON_FACTORY(MemInfo) MAKE_SINGLETON_FACTORY(MimeDatabase) +MAKE_SINGLETON_FACTORY(UrlUtils) MAKE_SINGLETON_FACTORY(UserAgentsModel) bool BrowserApplication::initialize(const QString& qmlFileSubPath @@ -202,6 +204,7 @@ bool BrowserApplication::initialize(const QString& qmlFileSubPath qmlRegisterSingletonType(uri, 0, 1, "MimeDatabase", MimeDatabase_singleton_factory); qmlRegisterType(uri, 0, 1, "SessionStorage"); qmlRegisterSingletonType(uri, 0, 1, "UserAgentsModel", UserAgentsModel_singleton_factory); + qmlRegisterSingletonType(uri, 0, 1, "UrlUtils", UrlUtils_singleton_factory); m_engine = new QQmlEngine; connect(m_engine, SIGNAL(quit()), SLOT(quit())); diff --git a/src/app/url-utils.cpp b/src/app/url-utils.cpp new file mode 100644 index 000000000..4dcb5654b --- /dev/null +++ b/src/app/url-utils.cpp @@ -0,0 +1,126 @@ +/* + * Copyright 2019 Chris Clime + * + * This file is part of morph-browser. + * + * morph-browser 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; version 3. + * + * morph-browser 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 this program. If not, see . + */ + +#include "url-utils.h" + +namespace +{ + const QString PdfViewerChromeExtension = "mhjfbmdgcfjbbpaeojofohoefgiehjai"; +} + +UrlUtils::UrlUtils(QObject* parent) : QObject(parent) +{ +} + +QUrl UrlUtils::urlFromString(const QString& urlString) const +{ + return QUrl(urlString); +} + +QString UrlUtils::extractScheme(const QUrl& url) const +{ + return url.scheme(); +} + +QString UrlUtils::removeScheme(const QUrl& url) const +{ + QString urlWithRemovedScheme = url.adjusted(QUrl::RemoveScheme).toString(); + + return urlWithRemovedScheme.startsWith("//") ? urlWithRemovedScheme.mid(2) : urlWithRemovedScheme; +} + +bool UrlUtils::schemeIs(const QUrl& url, const QString& expected) const +{ + return (extractScheme(url) == expected); +} + +bool UrlUtils::hasCustomScheme(const QUrl& url) const +{ + QStringList knownSchemes = { "chrome-extension", "http", "https", "file", "ftp", "data", "mailto" }; + + return (! knownSchemes.contains(extractScheme(url))); +} + +QString UrlUtils::extractHost(const QUrl& url) const +{ + return url.host(); +} + +bool UrlUtils::hostIs(const QUrl& url, const QString& expected) const +{ + return (extractHost(url) == expected); +} + +QUrl UrlUtils::fixUrl(const QString& urlString) const +{ + return QUrl::fromUserInput(urlString); +} + +bool UrlUtils::looksLikeAUrl(const QString& urlString) const +{ + QUrl url = QUrl::fromUserInput(urlString); + + // containing invalid chars, e.g. spaces + if (! url.isValid()) + { + return false; + } + + // local file URL (scheme file) + if (url.isLocalFile()) + { + return true; + } + + // it can still be, that the string is rather a search string, than a URL, e.g. a single word. + if (!urlString.startsWith(url.scheme())) + { + // check if there are dots in the host (IPv4 address or domain) + if (url.host().contains(".")) + { + return true; + } + + // check if it is an IPv6 address + // e.g. if host() is "::1", the host part is "[::1]" + QString hostPart = url.adjusted(QUrl::RemoveScheme | QUrl::RemoveUserInfo | QUrl::RemovePort | QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment).toString().mid(2); + + if (hostPart.startsWith("[") && hostPart.contains(":") && hostPart.endsWith("]")) + { + return true; + } + + // looks like a search (without spaces) + return false; + } + + // the url is valid (can have a custom scheme) + return true; +} + +QString UrlUtils::getPdfViewerExtensionUrlPrefix() const +{ + return QString("chrome-extension://%1/index.html?").arg(PdfViewerChromeExtension); +} + +bool UrlUtils::isPdfViewerExtensionUrl(const QUrl& url) const +{ + return url.toString().startsWith(getPdfViewerExtensionUrlPrefix()); +} + + diff --git a/src/app/url-utils.h b/src/app/url-utils.h new file mode 100644 index 000000000..9ac928d75 --- /dev/null +++ b/src/app/url-utils.h @@ -0,0 +1,78 @@ +/* + * Copyright 2019 Chris Clime + * + * This file is part of morph-browser. + * + * morph-browser 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; version 3. + * + * morph-browser 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 this program. If not, see . + */ + +#ifndef __URL_UTILS_H__ +#define __URL_UTILS_H__ + +#include +#include + +class UrlUtils : public QObject +{ + Q_OBJECT + +public: + explicit UrlUtils(QObject* parent=0); + + Q_INVOKABLE QUrl urlFromString(const QString& urlString) const; + Q_INVOKABLE QString extractScheme(const QUrl& url) const; + Q_INVOKABLE QString removeScheme(const QUrl& url) const; + Q_INVOKABLE bool schemeIs(const QUrl& url, const QString& expected) const; + Q_INVOKABLE bool hasCustomScheme(const QUrl& url) const; + Q_INVOKABLE QString extractHost(const QUrl& url) const; + Q_INVOKABLE bool hostIs(const QUrl& url, const QString& expected) const; + Q_INVOKABLE QUrl fixUrl(const QString& urlString) const; + Q_INVOKABLE bool looksLikeAUrl(const QString& urlString) const; + + // special extension urls + Q_INVOKABLE QString getPdfViewerExtensionUrlPrefix() const; + Q_INVOKABLE bool isPdfViewerExtensionUrl(const QUrl& url) const; + + // inline functions with url provided as string from QML + Q_INVOKABLE QString inline extractScheme(const QString& urlString) const + { + return extractScheme(QUrl(urlString)); + } + Q_INVOKABLE QString inline removeScheme(const QString& urlString) const + { + return removeScheme(QUrl(urlString)); + } + Q_INVOKABLE bool inline schemeIs(const QString& urlString, const QString& expected) const + { + return schemeIs(QUrl(urlString), expected); + } + Q_INVOKABLE bool inline hasCustomScheme(const QString& urlString) const + { + return hasCustomScheme(QUrl(urlString)); + } + Q_INVOKABLE QString inline extractHost(const QString& urlString) const + { + return extractHost(QUrl(urlString)); + } + Q_INVOKABLE bool inline hostIs(const QString& urlString, const QString& expected) const + { + return hostIs(QUrl(urlString), expected); + } + + Q_INVOKABLE bool inline isPdfViewerExtensionUrl(const QString& urlString) const + { + return isPdfViewerExtensionUrl(QUrl(urlString)); + } +}; + +#endif // __URL_UTILS_H__ diff --git a/src/app/webbrowser/AddressBar.qml b/src/app/webbrowser/AddressBar.qml index 65f432322..3ddb94bb0 100644 --- a/src/app/webbrowser/AddressBar.qml +++ b/src/app/webbrowser/AddressBar.qml @@ -19,8 +19,8 @@ import QtQuick 2.4 import Ubuntu.Components 1.3 import Ubuntu.Components.Popups 1.3 +import webbrowsercommon.private 0.1 import ".." -import "../UrlUtils.js" as UrlUtils FocusScope { id: addressbar diff --git a/src/app/webbrowser/Browser.qml b/src/app/webbrowser/Browser.qml index 39898441d..4a37a932e 100644 --- a/src/app/webbrowser/Browser.qml +++ b/src/app/webbrowser/Browser.qml @@ -30,7 +30,6 @@ import QtQuick.Controls 2.2 as QQC2 import webbrowserapp.private 0.1 import webbrowsercommon.private 0.1 import "../actions" as Actions -import "../UrlUtils.js" as UrlUtils import ".." as Common import "." as Local diff --git a/src/app/webbrowser/SettingsPage.qml b/src/app/webbrowser/SettingsPage.qml index e1f8a39e2..7004fe5e6 100644 --- a/src/app/webbrowser/SettingsPage.qml +++ b/src/app/webbrowser/SettingsPage.qml @@ -24,8 +24,8 @@ import Ubuntu.Components.Popups 1.3 import QtWebEngine 1.5 import Morph.Web 0.1 import webbrowserapp.private 0.1 +import webbrowsercommon.private 0.1 import ".." as Common -import "../UrlUtils.js" as UrlUtils FocusScope { id: settingsItem diff --git a/src/app/webbrowser/TabComponent.qml b/src/app/webbrowser/TabComponent.qml index bdb764f83..5318b7dd6 100644 --- a/src/app/webbrowser/TabComponent.qml +++ b/src/app/webbrowser/TabComponent.qml @@ -20,9 +20,9 @@ import QtQuick 2.4 import Ubuntu.Components 1.3 import Ubuntu.Components.Popups 1.3 import webbrowserapp.private 0.1 +import webbrowsercommon.private 0.1 import QtWebEngine 1.5 import "../actions" as Actions -import "../UrlUtils.js" as UrlUtils import ".." // FIXME: This component breaks encapsulation: it uses variables not defined in diff --git a/src/app/webcontainer/WebViewImplOxide.qml b/src/app/webcontainer/WebViewImplOxide.qml index ba96ef33e..e9dc7dfd6 100644 --- a/src/app/webcontainer/WebViewImplOxide.qml +++ b/src/app/webcontainer/WebViewImplOxide.qml @@ -23,7 +23,6 @@ import Ubuntu.Components.Popups 1.3 import QtWebEngine 1.7 import Morph.Web 0.1 import webbrowsercommon.private 0.1 -import "../UrlUtils.js" as UrlUtils import ".." WebappWebview { diff --git a/src/app/webcontainer/WebappContainerWebview.qml b/src/app/webcontainer/WebappContainerWebview.qml index 0776deab0..a0c3fa681 100644 --- a/src/app/webcontainer/WebappContainerWebview.qml +++ b/src/app/webcontainer/WebappContainerWebview.qml @@ -20,8 +20,8 @@ import QtQuick 2.4 import QtQuick.Window 2.2 import Ubuntu.Components 1.3 import Ubuntu.Unity.Action 1.1 as UnityActions +import webbrowsercommon.private 0.1 import "../actions" as Actions -import "../UrlUtils.js" as UrlUtils import ".." FocusScope { diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 5a637bb45..5d65fc276 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -24,4 +24,4 @@ add_subdirectory(downloads-model) add_subdirectory(single-instance-manager) add_subdirectory(meminfo) add_subdirectory(webapp-container-color-helper) - +add_subdirectory(url-utils) diff --git a/tests/unittests/url-utils/CMakeLists.txt b/tests/unittests/url-utils/CMakeLists.txt new file mode 100644 index 000000000..a7f504e1b --- /dev/null +++ b/tests/unittests/url-utils/CMakeLists.txt @@ -0,0 +1,13 @@ +find_package(Qt5Core REQUIRED) +find_package(Qt5Sql REQUIRED) +find_package(Qt5Test REQUIRED) +set(TEST tst_UrlUtilsTests) +add_executable(${TEST} tst_UrlUtilsTests.cpp) +include_directories(${morph-browser_SOURCE_DIR} ${webbrowser-common_SOURCE_DIR}) +target_link_libraries(${TEST} + Qt5::Core + Qt5::Sql + Qt5::Test + webbrowser-common +) +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) diff --git a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp new file mode 100644 index 000000000..bccf2bd21 --- /dev/null +++ b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp @@ -0,0 +1,134 @@ +/* + * Copyright 2013 Canonical Ltd. + * + * This file is part of webbrowser-app. + * + * webbrowser-app 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; version 3. + * + * webbrowser-app 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 this program. If not, see . + */ + +// Qt +#include + +// local +#include "url-utils.h" + +class UrlUtilsTests : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void test_extractHost_data() + { + QTest::addColumn("url"); + QTest::addColumn("host"); + QTest::newRow("row1") << QUrl("http://example.org/") << QString("www.example.org"); + QTest::newRow("row2") << QUrl("http://www.example.org/") << QString("www.example.org"); + QTest::newRow("row3") << QUrl("http://www.example.org/foo/bar") << QString("www.example.org"); + QTest::newRow("row4") << QUrl("http://example.org:2442/foo") << QString("example.org"); + QTest::newRow("row5") << QUrl("http://user:pwd@example.org/") << QString("example.org"); + QTest::newRow("row6") << QUrl("http://user:pwd@example.org:2442/") << QString("example.org"); + QTest::newRow("row7") << QUrl("ftp://user:pwd@example.org:21/foo/bar") << QString("example.org"); + } + + void test_extractHost() + { + QFETCH(QUrl, url); + QFETCH(QString, host); + UrlUtils urlUtils; + QCOMPARE(urlUtils.extractHost(url), host); + } + + void test_extractScheme_data() + { + QTest::addColumn("url"); + QTest::addColumn("scheme"); + QTest::newRow("row1") << QUrl("http://example.org/") << QString("http"); + QTest::newRow("row2") << QUrl("file://user:pwd@example.org:2442/") << QString("file"); + QTest::newRow("row3") << QUrl("file:///home/foo/bar.txt") << QString("file"); + QTest::newRow("row4") << QUrl("appid://com.ubuntu.terminal/terminal/current-user-version") << QString("appid"); + QTest::newRow("row5") << QUrl("www.example.org") << QString("http"); + } + + void test_extractScheme() + { + QFETCH(QUrl, url); + QFETCH(QString, scheme); + UrlUtils urlUtils; + QCOMPARE(urlUtils.extractScheme(url), scheme); + } + + void test_removeScheme_data() + { + QTest::addColumn("url"); + QTest::addColumn("removed"); + QTest::newRow("row1") << QUrl("http://example.org/") << QString("example.org/"); + QTest::newRow("row2") << QUrl("file://user:pwd@example.org:2442/") << QString("user:pwd@example.org:2442/"); + QTest::newRow("row3") << QUrl("file:///home/foo/bar.txt") << QString("/home/foo/bar.txt"); + QTest::newRow("row4") << QUrl("appid://com.ubuntu.terminal/terminal/current-user-version") << QString("com.ubuntu.terminal/terminal/current-user-version"); + QTest::newRow("row5") << QUrl("www.example.org") << QString("www.example.org"); + } + + void test_removeScheme() + { + QFETCH(QUrl, url); + QFETCH(QString, removed); + UrlUtils urlUtils; + QCOMPARE(urlUtils.removeScheme(url), removed); + } + + void test_looksLikeAUrl_data() + { + QTest::addColumn("urlString"); + QTest::addColumn("looksLike"); + QTest::newRow("row1") << QString("") << false; + QTest::newRow("row2") << QString("http://example.org/") << true; + QTest::newRow("row3") << QString("example.org") << true; + QTest::newRow("row4") << QString("http://www.example.org?q=foo bar") << false; + QTest::newRow("row5") << QString("about:blank") << true; + QTest::newRow("row6") << QString("file:///usr/foo/bar") << true; + QTest::newRow("row7") << QString("hello://my/name/is/") << true; + QTest::newRow("row8") << QString("192.168.1.0") << true; + QTest::newRow("row9") << QString("foo") << false; + QTest::newRow("row10") << QString("foo bar") << false; + } + + void test_looksLikeAUrl() + { + QFETCH(QString, urlString); + QFETCH(bool, looksLike); + UrlUtils urlUtils; + QCOMPARE(urlUtils.looksLikeAUrl(urlString), looksLike); + } + + void test_fixUrl_data() + { + QTest::addColumn("urlString"); + QTest::addColumn("fixedUrl"); + QTest::newRow("row1") << QString("About:BLANK") << QUrl("about:blank"); + QTest::newRow("row2") << QString("/usr/bin/") << QUrl("file:///usr/bin/"); + QTest::newRow("row3") << QString("example.org") << QUrl("http://example.org"); + } + + void test_fixUrl() + { + QFETCH(QString, urlString); + QFETCH(QUrl, fixedUrl); + UrlUtils urlUtils; + QCOMPARE(urlUtils.fixUrl(urlString), fixedUrl); + } + +}; + +QTEST_MAIN(UrlUtilsTests) +#include "tst_UrlUtilsTests.moc" From a9de6cba764122f6ae9c09c9cd694c05b4af22b6 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sat, 7 Aug 2021 21:54:37 +0200 Subject: [PATCH 02/10] adapt urlutils tests --- tests/unittests/qml/tst_UrlUtils.qml | 19 +------------------ tests/unittests/url-utils/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/tests/unittests/qml/tst_UrlUtils.qml b/tests/unittests/qml/tst_UrlUtils.qml index 9569833cd..1dee12318 100644 --- a/tests/unittests/qml/tst_UrlUtils.qml +++ b/tests/unittests/qml/tst_UrlUtils.qml @@ -17,28 +17,11 @@ */ import QtTest 1.0 -import "../../../src/app/UrlUtils.js" as UrlUtils +import webbrowsercommon.private 0.1 TestCase { name: "UrlUtils" - function test_extractAuthority_data() { - return [ - {url: "", authority: ""}, - {url: "http://example.org/", authority: "example.org"}, - {url: "http://www.example.org/", authority: "www.example.org"}, - {url: "http://www.example.org/foo/bar", authority: "www.example.org"}, - {url: "http://example.org:2442/foo", authority: "example.org:2442"}, - {url: "http://user:pwd@example.org/", authority: "user:pwd@example.org"}, - {url: "http://user:pwd@example.org:2442/", authority: "user:pwd@example.org:2442"}, - {url: "ftp://user:pwd@example.org:21/foo/bar", authority: "user:pwd@example.org:21"} - ] - } - - function test_extractAuthority(data) { - compare(UrlUtils.extractAuthority(data.url), data.authority) - } - function test_extractHost_data() { return [ {url: "http://example.org/", host: "example.org"}, diff --git a/tests/unittests/url-utils/CMakeLists.txt b/tests/unittests/url-utils/CMakeLists.txt index a7f504e1b..a1a0447c7 100644 --- a/tests/unittests/url-utils/CMakeLists.txt +++ b/tests/unittests/url-utils/CMakeLists.txt @@ -11,3 +11,4 @@ target_link_libraries(${TEST} webbrowser-common ) add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}) +set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal") From a6a48873db1e4f1a34e4397518defa5f6e3bfdd3 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sat, 7 Aug 2021 22:28:19 +0200 Subject: [PATCH 03/10] adapt urlutils unit test --- tests/unittests/qml/tst_QmlTests.cpp | 3 +++ tests/unittests/url-utils/tst_UrlUtilsTests.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/unittests/qml/tst_QmlTests.cpp b/tests/unittests/qml/tst_QmlTests.cpp index 4945ae85f..dd4d0210c 100644 --- a/tests/unittests/qml/tst_QmlTests.cpp +++ b/tests/unittests/qml/tst_QmlTests.cpp @@ -39,6 +39,7 @@ #include "searchengine.h" #include "tabs-model.h" #include "text-search-filter-model.h" +#include "url-utils.h" class TestContext : public QObject { @@ -167,6 +168,7 @@ MAKE_SINGLETON_FACTORY(BookmarksModel) MAKE_SINGLETON_FACTORY(HistoryModelMock) MAKE_SINGLETON_FACTORY(TestContext) MAKE_SINGLETON_FACTORY(Reparenter) +MAKE_SINGLETON_FACTORY(UrlUtils) int main(int argc, char** argv) { @@ -186,6 +188,7 @@ int main(int argc, char** argv) qmlRegisterType(browserUri, 0, 1, "LimitProxyModel"); qmlRegisterType(browserUri, 0, 1, "TextSearchFilterModel"); qmlRegisterSingletonType(browserUri, 0, 1, "Reparenter", Reparenter_singleton_factory); + qmlRegisterSingletonType(browserUri, 0, 1, "UrlUtils", UrlUtils_singleton_factory); const char* testUri = "webbrowsertest.private"; qmlRegisterSingletonType(testUri, 0, 1, "TestContext", TestContext_singleton_factory); diff --git a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp index bccf2bd21..5a00d479d 100644 --- a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp +++ b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp @@ -57,7 +57,7 @@ private Q_SLOTS: QTest::newRow("row2") << QUrl("file://user:pwd@example.org:2442/") << QString("file"); QTest::newRow("row3") << QUrl("file:///home/foo/bar.txt") << QString("file"); QTest::newRow("row4") << QUrl("appid://com.ubuntu.terminal/terminal/current-user-version") << QString("appid"); - QTest::newRow("row5") << QUrl("www.example.org") << QString("http"); + QTest::newRow("row5") << QUrl("www.example.org") << QString(""); } void test_extractScheme() @@ -94,7 +94,7 @@ private Q_SLOTS: QTest::newRow("row1") << QString("") << false; QTest::newRow("row2") << QString("http://example.org/") << true; QTest::newRow("row3") << QString("example.org") << true; - QTest::newRow("row4") << QString("http://www.example.org?q=foo bar") << false; + QTest::newRow("row4") << QString("http://www.example.org?q=foo bar") << true; QTest::newRow("row5") << QString("about:blank") << true; QTest::newRow("row6") << QString("file:///usr/foo/bar") << true; QTest::newRow("row7") << QString("hello://my/name/is/") << true; @@ -115,7 +115,7 @@ private Q_SLOTS: { QTest::addColumn("urlString"); QTest::addColumn("fixedUrl"); - QTest::newRow("row1") << QString("About:BLANK") << QUrl("about:blank"); + QTest::newRow("row1") << QString("About:BLANK") << QUrl("about:BLANK"); QTest::newRow("row2") << QString("/usr/bin/") << QUrl("file:///usr/bin/"); QTest::newRow("row3") << QString("example.org") << QUrl("http://example.org"); } From f51ee0e4965d95a0ac19c7a30fffac8bf38ced6b Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sat, 7 Aug 2021 23:25:48 +0200 Subject: [PATCH 04/10] remove UrlUtils qml test --- tests/unittests/qml/tst_QmlTests.cpp | 3 - tests/unittests/qml/tst_UrlUtils.qml | 83 ---------------------------- 2 files changed, 86 deletions(-) delete mode 100644 tests/unittests/qml/tst_UrlUtils.qml diff --git a/tests/unittests/qml/tst_QmlTests.cpp b/tests/unittests/qml/tst_QmlTests.cpp index dd4d0210c..4945ae85f 100644 --- a/tests/unittests/qml/tst_QmlTests.cpp +++ b/tests/unittests/qml/tst_QmlTests.cpp @@ -39,7 +39,6 @@ #include "searchengine.h" #include "tabs-model.h" #include "text-search-filter-model.h" -#include "url-utils.h" class TestContext : public QObject { @@ -168,7 +167,6 @@ MAKE_SINGLETON_FACTORY(BookmarksModel) MAKE_SINGLETON_FACTORY(HistoryModelMock) MAKE_SINGLETON_FACTORY(TestContext) MAKE_SINGLETON_FACTORY(Reparenter) -MAKE_SINGLETON_FACTORY(UrlUtils) int main(int argc, char** argv) { @@ -188,7 +186,6 @@ int main(int argc, char** argv) qmlRegisterType(browserUri, 0, 1, "LimitProxyModel"); qmlRegisterType(browserUri, 0, 1, "TextSearchFilterModel"); qmlRegisterSingletonType(browserUri, 0, 1, "Reparenter", Reparenter_singleton_factory); - qmlRegisterSingletonType(browserUri, 0, 1, "UrlUtils", UrlUtils_singleton_factory); const char* testUri = "webbrowsertest.private"; qmlRegisterSingletonType(testUri, 0, 1, "TestContext", TestContext_singleton_factory); diff --git a/tests/unittests/qml/tst_UrlUtils.qml b/tests/unittests/qml/tst_UrlUtils.qml deleted file mode 100644 index 1dee12318..000000000 --- a/tests/unittests/qml/tst_UrlUtils.qml +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2014 Canonical Ltd. - * - * This file is part of webbrowser-app. - * - * webbrowser-app 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; version 3. - * - * webbrowser-app 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 this program. If not, see . - */ - -import QtTest 1.0 -import webbrowsercommon.private 0.1 - -TestCase { - name: "UrlUtils" - - function test_extractHost_data() { - return [ - {url: "http://example.org/", host: "example.org"}, - {url: "http://www.example.org/", host: "www.example.org"}, - {url: "http://www.example.org/foo/bar", host: "www.example.org"}, - {url: "http://example.org:2442/foo", host: "example.org"}, - {url: "http://user:pwd@example.org/", host: "example.org"}, - {url: "http://user:pwd@example.org:2442/", host: "example.org"}, - {url: "ftp://user:pwd@example.org:21/foo/bar", host: "example.org"} - ] - } - - function test_extractHost(data) { - compare(UrlUtils.extractHost(data.url), data.host) - } - - function test_removeScheme_data() { - return [ - {url: "http://example.org/", removed: "example.org/"}, - {url: "file://user:pwd@example.org:2442/", removed: "user:pwd@example.org:2442/"}, - {url: "file:///home/foo/bar.txt", removed: "/home/foo/bar.txt"}, - {url: "ht+tp://www.example.org/", removed: "www.example.org/"}, - {url: "www.example.org", removed: "www.example.org"}, - ] - } - - function test_removeScheme(data) { - compare(UrlUtils.removeScheme(data.url), data.removed) - } - - function test_looksLikeAUrl_data() { - return [ - {url: "", looksLike: false}, - {url: "http://example.org/", looksLike: true}, - {url: "example.org", looksLike: true}, - {url: "http://www.example.org?q=foo bar", looksLike: false}, - {url: "about:blank", looksLike: true}, - {url: "file:///usr/foo/bar", looksLike: true}, - {url: "hello://my/name/is/", looksLike: true}, - {url: "192.168.1.0", looksLike: true} - ] - } - - function test_looksLikeAUrl(data) { - compare(UrlUtils.looksLikeAUrl(data.url), data.looksLike) - } - - function test_fixUrl_data() { - return [ - {url: "About:BLANK", fixed: "about:blank"}, - {url: "/usr/bin/", fixed: "file:///usr/bin/"}, - {url: "example.org", fixed: "http://example.org"} - ] - } - - function test_fixUrl(data) { - compare(UrlUtils.fixUrl(data.url), data.fixed) - } -} From 87b55f287621a1ce98c04dd16552e8398da4d49f Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 11:12:20 +0200 Subject: [PATCH 05/10] correct test (urlutils) and add new test row --- tests/unittests/url-utils/tst_UrlUtilsTests.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp index 5a00d479d..3e718e610 100644 --- a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp +++ b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp @@ -32,7 +32,7 @@ private Q_SLOTS: { QTest::addColumn("url"); QTest::addColumn("host"); - QTest::newRow("row1") << QUrl("http://example.org/") << QString("www.example.org"); + QTest::newRow("row1") << QUrl("http://example.org/") << QString("example.org"); QTest::newRow("row2") << QUrl("http://www.example.org/") << QString("www.example.org"); QTest::newRow("row3") << QUrl("http://www.example.org/foo/bar") << QString("www.example.org"); QTest::newRow("row4") << QUrl("http://example.org:2442/foo") << QString("example.org"); @@ -101,6 +101,7 @@ private Q_SLOTS: QTest::newRow("row8") << QString("192.168.1.0") << true; QTest::newRow("row9") << QString("foo") << false; QTest::newRow("row10") << QString("foo bar") << false; + QTest::newRow("row11") << QString("www.example.org search" << false); } void test_looksLikeAUrl() From fc17e4ea1974a1024e3c022ea75fc49f9bda343b Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 17:08:21 +0200 Subject: [PATCH 06/10] fix typo --- tests/unittests/url-utils/tst_UrlUtilsTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp index 3e718e610..d3878b121 100644 --- a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp +++ b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp @@ -101,7 +101,7 @@ private Q_SLOTS: QTest::newRow("row8") << QString("192.168.1.0") << true; QTest::newRow("row9") << QString("foo") << false; QTest::newRow("row10") << QString("foo bar") << false; - QTest::newRow("row11") << QString("www.example.org search" << false); + QTest::newRow("row11") << QString("www.example.org search") << false); } void test_looksLikeAUrl() From 8d7359359fbe3d34d3a1d295c4c79ba8afa62706 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 17:29:12 +0200 Subject: [PATCH 07/10] fix typo --- tests/unittests/url-utils/tst_UrlUtilsTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp index d3878b121..b9937a4a5 100644 --- a/tests/unittests/url-utils/tst_UrlUtilsTests.cpp +++ b/tests/unittests/url-utils/tst_UrlUtilsTests.cpp @@ -101,7 +101,7 @@ private Q_SLOTS: QTest::newRow("row8") << QString("192.168.1.0") << true; QTest::newRow("row9") << QString("foo") << false; QTest::newRow("row10") << QString("foo bar") << false; - QTest::newRow("row11") << QString("www.example.org search") << false); + QTest::newRow("row11") << QString("www.example.org search") << false; } void test_looksLikeAUrl() From f46f242fd649da30965fbce3f3815c1a8bddce88 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 19:34:48 +0200 Subject: [PATCH 08/10] make UrlUtils available for qml unittests --- tests/unittests/qml/CMakeLists.txt | 1 + tests/unittests/qml/tst_QmlTests.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tests/unittests/qml/CMakeLists.txt b/tests/unittests/qml/CMakeLists.txt index 2613a0829..d70582b7a 100644 --- a/tests/unittests/qml/CMakeLists.txt +++ b/tests/unittests/qml/CMakeLists.txt @@ -19,6 +19,7 @@ set(SOURCES ${morph-browser_SOURCE_DIR}/bookmarks-folder-model.cpp ${morph-browser_SOURCE_DIR}/bookmarks-folderlist-model.cpp ${webbrowser-common_SOURCE_DIR}/file-operations.cpp + ${webbrowser-common_SOURCE_DIR}/url-utils.cpp ${morph-browser_SOURCE_DIR}/history-domain-model.cpp ${morph-browser_SOURCE_DIR}/history-domainlist-model.cpp ${morph-browser_SOURCE_DIR}/history-model.cpp diff --git a/tests/unittests/qml/tst_QmlTests.cpp b/tests/unittests/qml/tst_QmlTests.cpp index 4945ae85f..ce367bb14 100644 --- a/tests/unittests/qml/tst_QmlTests.cpp +++ b/tests/unittests/qml/tst_QmlTests.cpp @@ -39,6 +39,7 @@ #include "searchengine.h" #include "tabs-model.h" #include "text-search-filter-model.h" +#include "url-utils.h" class TestContext : public QObject { @@ -167,12 +168,14 @@ MAKE_SINGLETON_FACTORY(BookmarksModel) MAKE_SINGLETON_FACTORY(HistoryModelMock) MAKE_SINGLETON_FACTORY(TestContext) MAKE_SINGLETON_FACTORY(Reparenter) +MAKE_SINGLETON_FACTORY(UrlUtils) int main(int argc, char** argv) { const char* commonUri = "webbrowsercommon.private"; qmlRegisterType(commonUri, 0, 1, "FaviconFetcher"); qmlRegisterSingletonType(commonUri, 0, 1, "FileOperations", FileOperations_singleton_factory); + qmlRegisterSingletonType(commonUri, 0, 1, "UrlUtils", UrlUtils_singleton_factory); const char* browserUri = "webbrowserapp.private"; qmlRegisterType(browserUri, 0, 1, "SearchEngine"); From c66672ad9fa195bcd899cc011921367b125cfb85 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 20:13:50 +0200 Subject: [PATCH 09/10] looksLikeAUrl() make check if url starts with its scheme case insensitive, the user might have typed ABOUT:blank instead of about:blank, or DATA:,text instead of data:,text --- src/app/url-utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/url-utils.cpp b/src/app/url-utils.cpp index 4dcb5654b..043b37c20 100644 --- a/src/app/url-utils.cpp +++ b/src/app/url-utils.cpp @@ -88,7 +88,7 @@ bool UrlUtils::looksLikeAUrl(const QString& urlString) const } // it can still be, that the string is rather a search string, than a URL, e.g. a single word. - if (!urlString.startsWith(url.scheme())) + if (!urlString.startsWith(url.scheme(), Qt::CaseInsensitive)) { // check if there are dots in the host (IPv4 address or domain) if (url.host().contains(".")) From 003c4a2b2bda77a6621842a9ba9e4bbf8813a0a1 Mon Sep 17 00:00:00 2001 From: Chris Clime Date: Sun, 8 Aug 2021 20:24:01 +0200 Subject: [PATCH 10/10] adapt adressbar tests --- tests/unittests/qml/tst_AddressBar.qml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/unittests/qml/tst_AddressBar.qml b/tests/unittests/qml/tst_AddressBar.qml index 00881c353..09045100d 100644 --- a/tests/unittests/qml/tst_AddressBar.qml +++ b/tests/unittests/qml/tst_AddressBar.qml @@ -90,11 +90,11 @@ Item { return [ {url: "file:///usr/share/doc/ubuntu-online-tour/index.html"}, {url: "http://ubuntu.com"}, - {url: "https://google.com"}, + {url: "https://ubports.com"}, {url: "ftp://ubuntu.com"}, {url: "about:blank"}, {url: "data:,A brief note"}, - {url: "http://com.google"} + {url: "http://com.ubports"} ] } @@ -198,9 +198,9 @@ Item { {text: "HTTPS://www.ubuntu.com", requestedUrl: "https://www.ubuntu.com"}, {text: "FILE:///usr/share/doc/ubuntu-online-tour/index.html", requestedUrl: "file:///usr/share/doc/ubuntu-online-tour/index.html"}, {text: "FTP://ubuntu.com", requestedUrl: "ftp://ubuntu.com"}, - {text: "ABOUT:BLANK", requestedUrl: "about:blank"}, + {text: "ABOUT:BLANK", requestedUrl: "about:BLANK"}, {text: "DATA:,A brief note", requestedUrl: "data:,A brief note"}, - {text: "HTTP://com.GOOGLE", requestedUrl: "http://com.google"} + {text: "HTTP://com.UBPORTS", requestedUrl: "http://com.ubports"} ] } @@ -250,9 +250,9 @@ Item { {input: "en.wikipedia.org/wiki/Foo", simplified: "en.wikipedia.org", actualUrl: "http://en.wikipedia.org/wiki/Foo"}, - {input: "http://com.google", - simplified: "com.google", - actualUrl: "http://com.google"}, + {input: "http://com.ubports", + simplified: "com.ubports", + actualUrl: "http://com.ubports"}, ] }