Merge remote-tracking branch 'upstream/master' into bdd_test_spawn_command
This commit is contained in:
commit
4a1ba45efa
@ -44,6 +44,8 @@ Changed
|
||||
- Improved detection of URLs/search terms when pasting multiple lines.
|
||||
- Don't remove `qutebrowser-editor-*` temporary file if editor subprocess crashed
|
||||
- Userscripts are also searched in `/usr/share/qutebrowser/userscripts`.
|
||||
- Blocked hosts are now also read from a `blocked-hosts` file in the config dir
|
||||
(e.g. `~/.config/qutebrowser/blocked-hosts`).
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
@ -62,6 +64,7 @@ Fixed
|
||||
- Fixed very long filenames when downloading `data://`-URLs.
|
||||
- Fixed ugly UI fonts on Windows when Liberation Mono is installed
|
||||
- Fixed crash when unbinding key from a section which doesn't exist in the config
|
||||
- Fixed report window after a segfault
|
||||
|
||||
v0.5.1
|
||||
------
|
||||
|
@ -102,6 +102,12 @@ $ rm -r qutebrowser-git
|
||||
|
||||
or you could use an AUR helper, e.g. `yaourt -S qutebrowser-git`.
|
||||
|
||||
If video or sound don't seem to work, try installing the gstreamer plugins:
|
||||
|
||||
----
|
||||
# pacman -S gst-plugins-{base,good,bad,ugly} gst-libav
|
||||
----
|
||||
|
||||
On Gentoo
|
||||
---------
|
||||
|
||||
@ -135,6 +141,21 @@ it with:
|
||||
$ nix-env -i qutebrowser
|
||||
----
|
||||
|
||||
On openSUSE
|
||||
-----------
|
||||
|
||||
There are prebuilt RPMs available for Tumbleweed and Leap 42.1:
|
||||
|
||||
http://software.opensuse.org/download.html?project=home%3Aarpraher&package=qutebrowser[One Click Install]
|
||||
|
||||
Or add the repo manually:
|
||||
|
||||
----
|
||||
# zypper addrepo http://download.opensuse.org/repositories/home:arpraher/openSUSE_Tumbleweed/home:arpraher.repo
|
||||
# zypper refresh
|
||||
# zypper install qutebrowser
|
||||
----
|
||||
|
||||
On Windows
|
||||
----------
|
||||
|
||||
@ -214,7 +235,16 @@ it as part of the packaging process.
|
||||
Installing qutebrowser with tox
|
||||
-------------------------------
|
||||
|
||||
Run tox inside the qutebrowser repository to set up a
|
||||
First of all, clone the repository using http://git-scm.org/[git] and switch
|
||||
into the repository folder:
|
||||
|
||||
----
|
||||
$ git clone https://github.com/The-Compiler/qutebrowser.git
|
||||
$ cd qutebrowser
|
||||
----
|
||||
|
||||
|
||||
Then run tox inside the qutebrowser repository to set up a
|
||||
https://docs.python.org/3/library/venv.html[virtual environment]:
|
||||
|
||||
----
|
||||
|
@ -165,10 +165,12 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Thorsten Wißmann
|
||||
* Austin Anderson
|
||||
* Alexey "Averrin" Nabrodov
|
||||
* avk
|
||||
* ZDarian
|
||||
* Milan Svoboda
|
||||
* John ShaggyTwoDope Jenkins
|
||||
* Peter Vilim
|
||||
* Clayton Craft
|
||||
* Oliver Caldwell
|
||||
* Philipp Hansch
|
||||
* Jonas Schürmann
|
||||
@ -191,7 +193,6 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Link
|
||||
* Larry Hynes
|
||||
* Johannes Altmanninger
|
||||
* avk
|
||||
* Samir Benmendil
|
||||
* Regina Hug
|
||||
* Mathias Fussenegger
|
||||
@ -199,9 +200,9 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Fritz V155 Reichwald
|
||||
* Franz Fellner
|
||||
* Corentin Jule
|
||||
* Clayton Craft
|
||||
* zwarag
|
||||
* xd1le
|
||||
* issue
|
||||
* haxwithaxe
|
||||
* evan
|
||||
* dylan araps
|
||||
|
@ -72,6 +72,8 @@
|
||||
=== adblock-update
|
||||
Update the adblock block lists.
|
||||
|
||||
This updates ~/.local/share/qutebrowser/blocked-hosts with downloaded host lists and re-reads ~/.config/qutebrowser/blocked-hosts.
|
||||
|
||||
[[back]]
|
||||
=== back
|
||||
Syntax: +:back [*--tab*] [*--bg*] [*--window*]+
|
||||
|
@ -4,19 +4,15 @@ MAINTAINER Florian Bruhin <me@the-compiler.org>
|
||||
RUN echo 'Server = http://mirror.de.leaseweb.net/archlinux/$repo/os/$arch' > /etc/pacman.d/mirrorlist
|
||||
RUN pacman-key --init && pacman-key --populate archlinux && pacman -Sy --noconfirm archlinux-keyring
|
||||
|
||||
RUN pacman-key -r 0xD6A1C70FE80A0C82 && \
|
||||
pacman-key --lsign-key 0xD6A1C70FE80A0C82 && \
|
||||
echo -e '[qt-debug]\nServer = http://qutebrowser.org/qt-debug/$arch' >> /etc/pacman.conf
|
||||
|
||||
RUN pacman -Suyy --noconfirm
|
||||
RUN pacman-db-upgrade
|
||||
|
||||
RUN pacman -S --noconfirm \
|
||||
git \
|
||||
python-tox \
|
||||
qt5-base-debug \
|
||||
qt5-webkit-debug \
|
||||
python-pyqt5-debug \
|
||||
qt5-base \
|
||||
qt5-webkit \
|
||||
python-pyqt5 \
|
||||
xorg-xinit \
|
||||
herbstluftwm \
|
||||
xorg-server-xvfb
|
||||
|
@ -92,9 +92,11 @@ class HostBlocker:
|
||||
|
||||
Attributes:
|
||||
_blocked_hosts: A set of blocked hosts.
|
||||
_config_blocked_hosts: A set of blocked hosts from ~/.config.
|
||||
_in_progress: The DownloadItems which are currently downloading.
|
||||
_done_count: How many files have been read successfully.
|
||||
_hosts_file: The path to the blocked-hosts file.
|
||||
_local_hosts_file: The path to the blocked-hosts file.
|
||||
_config_hosts_file: The path to a blocked-hosts in ~/.config
|
||||
|
||||
Class attributes:
|
||||
WHITELISTED: Hosts which never should be blocked.
|
||||
@ -105,13 +107,22 @@ class HostBlocker:
|
||||
|
||||
def __init__(self):
|
||||
self._blocked_hosts = set()
|
||||
self._config_blocked_hosts = set()
|
||||
self._in_progress = []
|
||||
self._done_count = 0
|
||||
|
||||
data_dir = standarddir.data()
|
||||
if data_dir is None:
|
||||
self._hosts_file = None
|
||||
self._local_hosts_file = None
|
||||
else:
|
||||
self._hosts_file = os.path.join(data_dir, 'blocked-hosts')
|
||||
self._local_hosts_file = os.path.join(data_dir, 'blocked-hosts')
|
||||
|
||||
config_dir = standarddir.config()
|
||||
if config_dir is None:
|
||||
self._config_hosts_file = None
|
||||
else:
|
||||
self._config_hosts_file = os.path.join(config_dir, 'blocked-hosts')
|
||||
|
||||
objreg.get('config').changed.connect(self.on_config_changed)
|
||||
|
||||
def is_blocked(self, url):
|
||||
@ -119,21 +130,46 @@ class HostBlocker:
|
||||
if not config.get('content', 'host-blocking-enabled'):
|
||||
return False
|
||||
host = url.host()
|
||||
return host in self._blocked_hosts and not is_whitelisted_host(host)
|
||||
return ((host in self._blocked_hosts or
|
||||
host in self._config_blocked_hosts) and
|
||||
not is_whitelisted_host(host))
|
||||
|
||||
def _read_hosts_file(self, filename, target):
|
||||
"""Read hosts from the given filename.
|
||||
|
||||
Args:
|
||||
filename: The file to read.
|
||||
target: The set to store the hosts in.
|
||||
|
||||
Return:
|
||||
True if a read was attempted, False otherwise
|
||||
"""
|
||||
if filename is None or not os.path.exists(filename):
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
target.add(line.strip())
|
||||
except OSError:
|
||||
log.misc.exception("Failed to read host blocklist!")
|
||||
|
||||
return True
|
||||
|
||||
def read_hosts(self):
|
||||
"""Read hosts from the existing blocked-hosts file."""
|
||||
self._blocked_hosts = set()
|
||||
if self._hosts_file is None:
|
||||
|
||||
if self._local_hosts_file is None:
|
||||
return
|
||||
if os.path.exists(self._hosts_file):
|
||||
try:
|
||||
with open(self._hosts_file, 'r', encoding='utf-8') as f:
|
||||
for line in f:
|
||||
self._blocked_hosts.add(line.strip())
|
||||
except OSError:
|
||||
log.misc.exception("Failed to read host blocklist!")
|
||||
else:
|
||||
|
||||
self._read_hosts_file(self._config_hosts_file,
|
||||
self._config_blocked_hosts)
|
||||
|
||||
found = self._read_hosts_file(self._local_hosts_file,
|
||||
self._blocked_hosts)
|
||||
|
||||
if not found:
|
||||
args = objreg.get('args')
|
||||
if (config.get('content', 'host-block-lists') is not None and
|
||||
args.basedir is None):
|
||||
@ -142,8 +178,14 @@ class HostBlocker:
|
||||
|
||||
@cmdutils.register(instance='host-blocker', win_id='win_id')
|
||||
def adblock_update(self, win_id):
|
||||
"""Update the adblock block lists."""
|
||||
if self._hosts_file is None:
|
||||
"""Update the adblock block lists.
|
||||
|
||||
This updates ~/.local/share/qutebrowser/blocked-hosts with downloaded
|
||||
host lists and re-reads ~/.config/qutebrowser/blocked-hosts.
|
||||
"""
|
||||
self._read_hosts_file(self._config_hosts_file,
|
||||
self._config_blocked_hosts)
|
||||
if self._local_hosts_file is None:
|
||||
raise cmdexc.CommandError("No data storage is configured!")
|
||||
self._blocked_hosts = set()
|
||||
self._done_count = 0
|
||||
@ -221,7 +263,7 @@ class HostBlocker:
|
||||
|
||||
def on_lists_downloaded(self):
|
||||
"""Install block lists after files have been downloaded."""
|
||||
with open(self._hosts_file, 'w', encoding='utf-8') as f:
|
||||
with open(self._local_hosts_file, 'w', encoding='utf-8') as f:
|
||||
for host in sorted(self._blocked_hosts):
|
||||
f.write(host + '\n')
|
||||
message.info('current', "adblock: Read {} hosts from {} sources."
|
||||
@ -233,7 +275,7 @@ class HostBlocker:
|
||||
urls = config.get('content', 'host-block-lists')
|
||||
if urls is None:
|
||||
try:
|
||||
os.remove(self._hosts_file)
|
||||
os.remove(self._local_hosts_file)
|
||||
except OSError:
|
||||
log.misc.exception("Failed to delete hosts file.")
|
||||
|
||||
|
@ -23,8 +23,6 @@ import urllib.parse
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
|
||||
|
||||
from qutebrowser.misc import httpclient
|
||||
|
||||
|
||||
class PastebinClient(QObject):
|
||||
|
||||
@ -47,11 +45,17 @@ class PastebinClient(QObject):
|
||||
success = pyqtSignal(str)
|
||||
error = pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, client, parent=None):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
client: The HTTPClient to use. Will be reparented.
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self._client = httpclient.HTTPClient(self)
|
||||
self._client.error.connect(self.error)
|
||||
self._client.success.connect(self.on_client_success)
|
||||
client.setParent(self)
|
||||
client.error.connect(self.error)
|
||||
client.success.connect(self.on_client_success)
|
||||
self._client = client
|
||||
|
||||
def paste(self, name, title, text, parent=None):
|
||||
"""Paste the text into a pastebin and return the URL.
|
||||
|
@ -219,14 +219,12 @@ class BrowserPage(QWebPage):
|
||||
def _show_pdfjs(self, reply):
|
||||
"""Show the reply with pdfjs."""
|
||||
try:
|
||||
page = pdfjs.generate_pdfjs_page(reply.url()).encode('utf-8')
|
||||
page = pdfjs.generate_pdfjs_page(reply.url())
|
||||
except pdfjs.PDFJSNotFound:
|
||||
# pylint: disable=no-member
|
||||
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/490/
|
||||
page = (jinja.env.get_template('no_pdfjs.html')
|
||||
.render(url=reply.url().toDisplayString())
|
||||
.encode('utf-8'))
|
||||
self.mainFrame().setContent(page, 'text/html', reply.url())
|
||||
page = jinja.render('no_pdfjs.html',
|
||||
url=reply.url().toDisplayString())
|
||||
self.mainFrame().setContent(page.encode('utf-8'), 'text/html',
|
||||
reply.url())
|
||||
reply.deleteLater()
|
||||
|
||||
def shutdown(self):
|
||||
|
22
qutebrowser/html/undef_error.html
Normal file
22
qutebrowser/html/undef_error.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Error while rendering HTML</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Error while rendering internal qutebrowser page</h1>
|
||||
<p>There was an error while rendering {pagename}.</p>
|
||||
|
||||
<p>This most likely happened because you updated qutebrowser but didn't restart yet.</p>
|
||||
|
||||
<p>If you believe this isn't the case and this is a bug, please do :report.<p>
|
||||
|
||||
<h2>Traceback</h2>
|
||||
<pre>{traceback}</pre>
|
||||
</body>
|
||||
</html>
|
@ -36,7 +36,7 @@ from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
|
||||
|
||||
import qutebrowser
|
||||
from qutebrowser.utils import version, log, utils, objreg, qtutils
|
||||
from qutebrowser.misc import miscwidgets, autoupdate, msgbox
|
||||
from qutebrowser.misc import miscwidgets, autoupdate, msgbox, httpclient
|
||||
from qutebrowser.browser.network import pastebin
|
||||
from qutebrowser.config import config
|
||||
|
||||
@ -141,7 +141,8 @@ class _CrashDialog(QDialog):
|
||||
self.setWindowTitle("Whoops!")
|
||||
self.resize(QSize(640, 600))
|
||||
self._vbox = QVBoxLayout(self)
|
||||
self._paste_client = pastebin.PastebinClient(self)
|
||||
http_client = httpclient.HTTPClient()
|
||||
self._paste_client = pastebin.PastebinClient(http_client, self)
|
||||
self._pypi_client = autoupdate.PyPIVersionClient(self)
|
||||
self._init_text()
|
||||
|
||||
@ -508,11 +509,23 @@ class FatalCrashDialog(_CrashDialog):
|
||||
def _init_text(self):
|
||||
super()._init_text()
|
||||
text = ("<b>qutebrowser was restarted after a fatal crash.</b><br/>"
|
||||
"<br/>Note: Crash reports for fatal crashes sometimes don't "
|
||||
"QTWEBENGINE_NOTE"
|
||||
"<br/>Crash reports for fatal crashes sometimes don't "
|
||||
"contain the information necessary to fix an issue. Please "
|
||||
"follow the steps in <a href='https://github.com/The-Compiler/"
|
||||
"qutebrowser/blob/master/doc/stacktrace.asciidoc'>"
|
||||
"stacktrace.asciidoc</a> to submit a stacktrace.<br/>")
|
||||
|
||||
if datetime.datetime.now() < datetime.datetime(2016, 4, 23):
|
||||
note = ("<br/>Fatal crashes like this are often caused by the "
|
||||
"current QtWebKit backend.<br/><b>I'm currently running a "
|
||||
"crowdfunding for the new QtWebEngine backend, based on "
|
||||
"Chromium:</b> <a href='http://igg.me/at/qutebrowser'>"
|
||||
"igg.me/at/qutebrowser</a><br/>")
|
||||
text = text.replace('QTWEBENGINE_NOTE', note)
|
||||
else:
|
||||
text = text.replace('QTWEBENGINE_NOTE', '')
|
||||
|
||||
self._lbl.setText(text)
|
||||
|
||||
def _init_checkboxes(self):
|
||||
|
@ -72,7 +72,7 @@ class CrashHandler(QObject):
|
||||
|
||||
def handle_segfault(self):
|
||||
"""Handle a segfault from a previous run."""
|
||||
data_dir = None
|
||||
data_dir = standarddir.data()
|
||||
if data_dir is None:
|
||||
return
|
||||
logname = os.path.join(data_dir, 'crash.log')
|
||||
|
@ -21,10 +21,12 @@
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import traceback
|
||||
|
||||
import jinja2
|
||||
import jinja2.exceptions
|
||||
|
||||
from qutebrowser.utils import utils
|
||||
from qutebrowser.utils import utils, log
|
||||
|
||||
from PyQt5.QtCore import QUrl
|
||||
|
||||
@ -74,8 +76,14 @@ def resource_url(path):
|
||||
|
||||
def render(template, **kwargs):
|
||||
"""Render the given template and pass the given arguments to it."""
|
||||
return _env.get_template(template).render(**kwargs)
|
||||
|
||||
try:
|
||||
return _env.get_template(template).render(**kwargs)
|
||||
except jinja2.exceptions.UndefinedError:
|
||||
log.misc.exception("UndefinedError while rendering " + template)
|
||||
err_path = os.path.join('html', 'undef_error.html')
|
||||
err_template = utils.read_file(err_path)
|
||||
tb = traceback.format_exc()
|
||||
return err_template.format(pagename=template, traceback=tb)
|
||||
|
||||
_env = jinja2.Environment(loader=Loader('html'), autoescape=_guess_autoescape)
|
||||
_env.globals['resource_url'] = resource_url
|
||||
|
@ -65,6 +65,8 @@ PERFECT_FILES = [
|
||||
'qutebrowser/browser/network/filescheme.py'),
|
||||
('tests/unit/browser/network/test_networkreply.py',
|
||||
'qutebrowser/browser/network/networkreply.py'),
|
||||
('tests/unit/browser/network/test_pastebin.py',
|
||||
'qutebrowser/browser/network/pastebin.py'),
|
||||
('tests/unit/browser/test_signalfilter.py',
|
||||
'qutebrowser/browser/signalfilter.py'),
|
||||
|
||||
@ -102,6 +104,8 @@ PERFECT_FILES = [
|
||||
'qutebrowser/mainwindow/statusbar/textbase.py'),
|
||||
('tests/unit/mainwindow/statusbar/test_prompt.py',
|
||||
'qutebrowser/mainwindow/statusbar/prompt.py'),
|
||||
('tests/unit/mainwindow/statusbar/test_url.py',
|
||||
'qutebrowser/mainwindow/statusbar/url.py'),
|
||||
|
||||
('tests/unit/config/test_configtypes.py',
|
||||
'qutebrowser/config/configtypes.py'),
|
||||
|
@ -31,23 +31,27 @@ import argparse
|
||||
def main():
|
||||
args = get_args()
|
||||
if args.browser in ['chromium', 'firefox', 'ie']:
|
||||
import_netscape_bookmarks(args.bookmarks)
|
||||
import_netscape_bookmarks(args.bookmarks, args.bookmark_format)
|
||||
|
||||
|
||||
def get_args():
|
||||
"""Get the argparse parser."""
|
||||
parser = argparse.ArgumentParser(
|
||||
epilog="To import bookmarks from Chromium, Firefox or IE, "
|
||||
"export them to HTML in your browsers bookmark manager.")
|
||||
parser.add_argument('browser', help="Which browser?",
|
||||
"export them to HTML in your browsers bookmark manager. "
|
||||
"By default, this script will output in a quickmarks format.")
|
||||
parser.add_argument('browser', help="Which browser? (chromium, firefox)",
|
||||
choices=['chromium', 'firefox', 'ie'],
|
||||
metavar='browser')
|
||||
parser.add_argument('bookmarks', help="Bookmarks file")
|
||||
parser.add_argument('-b', help="Output in bookmark format.",
|
||||
dest='bookmark_format', action='store_true',
|
||||
default=False, required=False)
|
||||
parser.add_argument('bookmarks', help="Bookmarks file (html format)")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def import_netscape_bookmarks(bookmarks_file):
|
||||
def import_netscape_bookmarks(bookmarks_file, is_bookmark_format):
|
||||
"""Import bookmarks from a NETSCAPE-Bookmark-file v1.
|
||||
|
||||
Generated by Chromium, Firefox, IE and possibly more browsers
|
||||
@ -57,11 +61,15 @@ def import_netscape_bookmarks(bookmarks_file):
|
||||
soup = bs4.BeautifulSoup(f, 'html.parser')
|
||||
|
||||
html_tags = soup.findAll('a')
|
||||
if is_bookmark_format:
|
||||
output_template = '{tag[href]} {tag.string}'
|
||||
else:
|
||||
output_template = '{tag.string} {tag[href]}'
|
||||
|
||||
bookmarks = []
|
||||
for tag in html_tags:
|
||||
if tag['href'] not in bookmarks:
|
||||
bookmarks.append('{tag.string} {tag[href]}'.format(tag=tag))
|
||||
bookmarks.append(output_template.format(tag=tag))
|
||||
|
||||
for bookmark in bookmarks:
|
||||
print(bookmark)
|
||||
|
125
tests/unit/browser/network/test_pastebin.py
Normal file
125
tests/unit/browser/network/test_pastebin.py
Normal file
@ -0,0 +1,125 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2016 Anna Kobak (avk) <awerk@onet.eu>:
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pytest
|
||||
from PyQt5.QtCore import pyqtSignal, QUrl, QObject
|
||||
|
||||
from qutebrowser.browser.network import pastebin
|
||||
from qutebrowser.misc import httpclient
|
||||
|
||||
|
||||
class HTTPPostStub(QObject):
|
||||
|
||||
"""A stub class for HTTPClient.
|
||||
|
||||
Attributes:
|
||||
url: the last url send by post()
|
||||
data: the last data send by post()
|
||||
"""
|
||||
|
||||
success = pyqtSignal(str)
|
||||
error = pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.url = None
|
||||
self.data = None
|
||||
|
||||
def post(self, url, data=None):
|
||||
self.url = url
|
||||
self.data = data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pbclient():
|
||||
http_stub = HTTPPostStub()
|
||||
client = pastebin.PastebinClient(http_stub)
|
||||
return client
|
||||
|
||||
|
||||
def test_constructor(qapp):
|
||||
http_client = httpclient.HTTPClient()
|
||||
pbclient = pastebin.PastebinClient(http_client)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
{
|
||||
"name": "XYZ",
|
||||
"title": "hello world",
|
||||
"text": "xyz. 123 \n 172ANB",
|
||||
"reply": "abc"
|
||||
},
|
||||
{
|
||||
"name": "the name",
|
||||
"title": "the title",
|
||||
"text": "some Text",
|
||||
"reply": "some parent"
|
||||
}
|
||||
])
|
||||
def test_paste_with_parent(data, pbclient):
|
||||
http_stub = pbclient._client
|
||||
pbclient.paste(data["name"], data["title"], data["text"], data["reply"])
|
||||
assert http_stub.data == data
|
||||
assert http_stub.url == QUrl('http://paste.the-compiler.org/api/create')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data', [
|
||||
{
|
||||
"name": "XYZ",
|
||||
"title": "hello world",
|
||||
"text": "xyz. 123 \n 172ANB"
|
||||
},
|
||||
{
|
||||
"name": "the name",
|
||||
"title": "the title",
|
||||
"text": "some Text"
|
||||
}
|
||||
])
|
||||
def test_paste_without_parent(data, pbclient):
|
||||
http_stub = pbclient._client
|
||||
pbclient.paste(data["name"], data["title"], data["text"])
|
||||
assert pbclient._client.data == data
|
||||
assert http_stub.url == QUrl('http://paste.the-compiler.org/api/create')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('http', [
|
||||
"http://paste.the-compiler.org/view/ges83nt3",
|
||||
"http://paste.the-compiler.org/view/3gjnwg4"
|
||||
])
|
||||
def test_on_client_success(http, pbclient, qtbot):
|
||||
with qtbot.assertNotEmitted(pbclient.error):
|
||||
with qtbot.waitSignal(pbclient.success):
|
||||
pbclient._client.success.emit(http)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('http', [
|
||||
"http invalid",
|
||||
"http:/invalid.org"
|
||||
"http//invalid.com"
|
||||
])
|
||||
def test_client_success_invalid_http(http, pbclient, qtbot):
|
||||
with qtbot.assertNotEmitted(pbclient.success):
|
||||
with qtbot.waitSignal(pbclient.error):
|
||||
pbclient._client.success.emit(http)
|
||||
|
||||
|
||||
def test_client_error(pbclient, qtbot):
|
||||
with qtbot.assertNotEmitted(pbclient.success):
|
||||
with qtbot.waitSignal(pbclient.error):
|
||||
pbclient._client.error.emit("msg")
|
146
tests/unit/mainwindow/statusbar/test_url.py
Normal file
146
tests/unit/mainwindow/statusbar/test_url.py
Normal file
@ -0,0 +1,146 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2016 Clayton Craft (craftyguy) <craftyguy@gmail.com>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Test Statusbar url."""
|
||||
|
||||
import pytest
|
||||
import collections
|
||||
|
||||
from qutebrowser.browser import webview
|
||||
from qutebrowser.mainwindow.statusbar import url
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tab_widget():
|
||||
"""Fixture providing a fake tab widget."""
|
||||
tab = collections.namedtuple('Tab', 'cur_url load_status')
|
||||
tab.cur_url = collections.namedtuple('cur_url', 'toDisplayString')
|
||||
return tab
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def url_widget(qtbot, monkeypatch, config_stub):
|
||||
"""Fixture providing a Url widget."""
|
||||
config_stub.data = {
|
||||
'colors': {
|
||||
'statusbar.url.bg': 'white',
|
||||
'statusbar.url.fg': 'black',
|
||||
'statusbar.url.fg.success': 'yellow',
|
||||
'statusbar.url.fg.success.https': 'green',
|
||||
'statusbar.url.fg.error': 'red',
|
||||
'statusbar.url.fg.warn': 'orange',
|
||||
'statusbar.url.fg.hover': 'blue'
|
||||
},
|
||||
'fonts': {},
|
||||
}
|
||||
monkeypatch.setattr(
|
||||
'qutebrowser.mainwindow.statusbar.url.style.config', config_stub)
|
||||
widget = url.UrlText()
|
||||
qtbot.add_widget(widget)
|
||||
assert not widget.isVisible()
|
||||
return widget
|
||||
|
||||
|
||||
@pytest.mark.parametrize('url_text', [
|
||||
'http://abc123.com/this/awesome/url.html',
|
||||
'https://supersecret.gov/nsa/files.txt',
|
||||
'Th1$ i$ n0t @ n0rm@L uRL! P@n1c! <-->',
|
||||
None
|
||||
])
|
||||
def test_set_url(url_widget, url_text):
|
||||
"""Test text displayed by the widget."""
|
||||
url_widget.set_url(url_text)
|
||||
if url_text is not None:
|
||||
assert url_widget.text() == url_text
|
||||
else:
|
||||
assert url_widget.text() == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize('url_text, title, text', [
|
||||
('http://abc123.com/this/awesome/url.html', 'Awesome site', 'click me!'),
|
||||
('https://supersecret.gov/nsa/files.txt', 'Secret area', None),
|
||||
('Th1$ i$ n0t @ n0rm@L uRL! P@n1c! <-->', 'Probably spam', 'definitely'),
|
||||
(None, None, 'did I break?!')
|
||||
])
|
||||
def test_set_hover_url(url_widget, url_text, title, text):
|
||||
"""Test text when hovering over a link."""
|
||||
url_widget.set_hover_url(url_text, title, text)
|
||||
if url_text is not None:
|
||||
assert url_widget.text() == url_text
|
||||
assert url_widget._urltype == url.UrlType.hover
|
||||
else:
|
||||
assert url_widget.text() == ''
|
||||
assert url_widget._urltype == url.UrlType.normal
|
||||
|
||||
|
||||
@pytest.mark.parametrize('status, expected', [
|
||||
(webview.LoadStatus.success, url.UrlType.success),
|
||||
(webview.LoadStatus.success_https, url.UrlType.success_https),
|
||||
(webview.LoadStatus.error, url.UrlType.error),
|
||||
(webview.LoadStatus.warn, url.UrlType.warn),
|
||||
(webview.LoadStatus.loading, url.UrlType.normal),
|
||||
(webview.LoadStatus.none, url.UrlType.normal)
|
||||
])
|
||||
def test_on_load_status_changed(url_widget, status, expected):
|
||||
"""Test text when status is changed."""
|
||||
url_widget.set_url('www.example.com')
|
||||
url_widget.on_load_status_changed(status.name)
|
||||
assert url_widget._urltype == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize('load_status, url_text', [
|
||||
(url.UrlType.success, 'http://abc123.com/this/awesome/url.html'),
|
||||
(url.UrlType.success, 'http://reddit.com/r/linux'),
|
||||
(url.UrlType.success_https, 'www.google.com'),
|
||||
(url.UrlType.success_https, 'https://supersecret.gov/nsa/files.txt'),
|
||||
(url.UrlType.warn, 'www.shadysite.org/some/path/to/file/with/issues.htm'),
|
||||
(url.UrlType.error, 'Th1$ i$ n0t @ n0rm@L uRL! P@n1c! <-->'),
|
||||
(url.UrlType.error, None)
|
||||
])
|
||||
def test_on_tab_changed(url_widget, tab_widget, load_status, url_text):
|
||||
tab_widget.load_status = load_status
|
||||
tab_widget.cur_url.toDisplayString = lambda: url_text
|
||||
url_widget.on_tab_changed(tab_widget)
|
||||
if url_text is not None:
|
||||
assert url_widget._urltype == load_status
|
||||
assert url_widget.text() == url_text
|
||||
else:
|
||||
assert url_widget._urltype == url.UrlType.normal
|
||||
assert url_widget.text() == ''
|
||||
|
||||
|
||||
@pytest.mark.parametrize('url_text, load_status, expected_status', [
|
||||
('http://abc123.com/this/awesome/url.html', webview.LoadStatus.success,
|
||||
url.UrlType.success),
|
||||
('https://supersecret.gov/nsa/files.txt', webview.LoadStatus.success_https,
|
||||
url.UrlType.success_https),
|
||||
('Th1$ i$ n0t @ n0rm@L uRL! P@n1c! <-->', webview.LoadStatus.error,
|
||||
url.UrlType.error),
|
||||
('http://www.qutebrowser.org/CONTRIBUTING.html', webview.LoadStatus.loading,
|
||||
url.UrlType.normal),
|
||||
('www.whatisthisurl.com', webview.LoadStatus.warn, url.UrlType.warn)
|
||||
])
|
||||
def test_normal_url(url_widget, url_text, load_status, expected_status):
|
||||
url_widget.set_url(url_text)
|
||||
url_widget.on_load_status_changed(load_status.name)
|
||||
url_widget.set_hover_url(url_text, "", "")
|
||||
url_widget.set_hover_url("", "", "")
|
||||
assert url_widget.text() == url_text
|
||||
assert url_widget._urltype == expected_status
|
@ -23,21 +23,28 @@ import os
|
||||
import os.path
|
||||
|
||||
import pytest
|
||||
import logging
|
||||
import jinja2
|
||||
from PyQt5.QtCore import QUrl
|
||||
|
||||
from qutebrowser.utils import jinja
|
||||
from qutebrowser.utils import utils, jinja
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_read_file(monkeypatch):
|
||||
"""pytest fixture to patch utils.read_file."""
|
||||
real_read_file = utils.read_file
|
||||
|
||||
def _read_file(path):
|
||||
"""A read_file which returns a simple template if the path is right."""
|
||||
if path == os.path.join('html', 'test.html'):
|
||||
return """Hello {{var}}"""
|
||||
elif path == os.path.join('html', 'test2.html'):
|
||||
return """{{ resource_url('utils/testfile') }}"""
|
||||
elif path == os.path.join('html', 'undef.html'):
|
||||
return """{{ does_not_exist() }}"""
|
||||
elif path == os.path.join('html', 'undef_error.html'):
|
||||
return real_read_file(path)
|
||||
else:
|
||||
raise IOError("Invalid path {}!".format(path))
|
||||
|
||||
@ -87,6 +94,18 @@ def test_utf8():
|
||||
assert data == "Hello \u2603"
|
||||
|
||||
|
||||
def test_undefined_function(caplog):
|
||||
"""Make sure we don't crash if an undefined function is called."""
|
||||
with caplog.at_level(logging.ERROR):
|
||||
data = jinja.render('undef.html')
|
||||
assert 'There was an error while rendering undef.html' in data
|
||||
assert "'does_not_exist' is undefined" in data
|
||||
assert data.startswith('<!DOCTYPE html>')
|
||||
|
||||
assert len(caplog.records) == 1
|
||||
assert caplog.records[0].msg == "UndefinedError while rendering undef.html"
|
||||
|
||||
|
||||
@pytest.mark.parametrize('name, expected', [
|
||||
(None, False),
|
||||
('foo', False),
|
||||
|
12
tox.ini
12
tox.ini
@ -37,17 +37,17 @@ deps =
|
||||
pytest-instafail==0.3.0
|
||||
pytest-travis-fold==1.2.0
|
||||
pytest-repeat==0.2
|
||||
pytest-rerunfailures==1.0.1
|
||||
pytest-rerunfailures==1.0.2
|
||||
pytest-xvfb==0.2.0
|
||||
six==1.10.0
|
||||
termcolor==1.1.0
|
||||
vulture==0.8.1
|
||||
Werkzeug==0.11.4
|
||||
Werkzeug==0.11.5
|
||||
wheel==0.29.0
|
||||
cherrypy==5.1.0
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test {posargs:tests}
|
||||
{envpython} -m pytest {posargs:tests}
|
||||
|
||||
[testenv:py35-cov]
|
||||
basepython = python3.5
|
||||
@ -56,7 +56,7 @@ passenv = {[testenv]passenv}
|
||||
deps = {[testenv]deps}
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
|
||||
{envpython} -m pytest --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
|
||||
{envpython} scripts/dev/check_coverage.py {posargs}
|
||||
|
||||
[testenv:py34-cov]
|
||||
@ -66,7 +66,7 @@ passenv = {[testenv]passenv}
|
||||
deps = {[testenv]deps}
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
|
||||
{envpython} -m pytest --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
|
||||
{envpython} scripts/dev/check_coverage.py {posargs}
|
||||
|
||||
[testenv:mkvenv]
|
||||
@ -99,7 +99,7 @@ setenv =
|
||||
QUTE_NO_DISPLAY=1
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test {posargs:tests}
|
||||
{envpython} -m pytest {posargs:tests}
|
||||
|
||||
[testenv:misc]
|
||||
ignore_errors = true
|
||||
|
Loading…
Reference in New Issue
Block a user