Merge branch 'download-page-tests' of https://github.com/The-Compiler/qutebrowser into download-page
This commit is contained in:
commit
62b0c4d178
@ -48,6 +48,8 @@ Added
|
||||
* `colors -> downloads.bg.system`
|
||||
- New command `:download-retry` to retry a failed download.
|
||||
- New command `:download-clear` which replaces `:download-remove --all`.
|
||||
- `:set-cmd-text` has a new `--append` argument to append to the current
|
||||
statusbar text.
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
@ -82,6 +84,8 @@ Fixed
|
||||
- Fixed a crash when a website presents a very small favicon.
|
||||
- Fixed prompting for download directory when
|
||||
`storage -> prompt-download-directory` was unset.
|
||||
- Fixed crash when using `:follow-hint` outside of hint mode.
|
||||
- Fixed crash when using `:set foo bar?` with invalid section/option.
|
||||
|
||||
v0.4.1
|
||||
------
|
||||
|
@ -140,9 +140,9 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Florian Bruhin
|
||||
* Antoni Boucher
|
||||
* Bruno Oliveira
|
||||
* Lamar Pavel
|
||||
* Alexander Cogneau
|
||||
* Martin Tournoij
|
||||
* Lamar Pavel
|
||||
* Raphael Pierzina
|
||||
* Joel Torstensson
|
||||
* Daniel
|
||||
|
@ -577,7 +577,7 @@ If the option name ends with '?', the value of the option is shown instead. If t
|
||||
|
||||
[[set-cmd-text]]
|
||||
=== set-cmd-text
|
||||
Syntax: +:set-cmd-text [*--space*] 'text'+
|
||||
Syntax: +:set-cmd-text [*--space*] [*--append*] 'text'+
|
||||
|
||||
Preset the statusbar to some text.
|
||||
|
||||
@ -586,6 +586,7 @@ Preset the statusbar to some text.
|
||||
|
||||
==== optional arguments
|
||||
* +*-s*+, +*--space*+: If given, a space is added to the end.
|
||||
* +*-a*+, +*--append*+: If given, the text is appended to the current text.
|
||||
|
||||
==== note
|
||||
* This command does not split arguments after the last argument and handles quotes literally.
|
||||
|
@ -35,3 +35,4 @@ qt_log_ignore =
|
||||
^Type conversion already registered from type .*
|
||||
^QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once\.
|
||||
^QWaitCondition: Destroyed while threads are still waiting
|
||||
^QXcbXSettings::QXcbXSettings\(QXcbScreen\*\) Failed to get selection owner for XSETTINGS_S atom
|
||||
|
@ -65,7 +65,8 @@ class DiskCache(QNetworkDiskCache):
|
||||
"""Update cache size/activated if the config was changed."""
|
||||
if (section, option) == ('storage', 'cache-size'):
|
||||
self.setMaximumCacheSize(config.get('storage', 'cache-size'))
|
||||
elif (section, option) == ('general', 'private-browsing'):
|
||||
elif (section, option) == ('general', # pragma: no branch
|
||||
'private-browsing'):
|
||||
self._maybe_activate()
|
||||
|
||||
def cacheSize(self):
|
||||
|
@ -810,10 +810,15 @@ class DownloadManager(QAbstractListModel):
|
||||
download = DownloadItem(reply, self._win_id, self)
|
||||
download.cancelled.connect(
|
||||
functools.partial(self.remove_item, download))
|
||||
|
||||
delay = config.get('ui', 'remove-finished-downloads')
|
||||
if delay > -1 or auto_remove:
|
||||
if delay > -1:
|
||||
download.finished.connect(
|
||||
functools.partial(self.remove_item_delayed, download, delay))
|
||||
elif auto_remove:
|
||||
download.finished.connect(
|
||||
functools.partial(self.remove_item, download))
|
||||
|
||||
download.data_changed.connect(
|
||||
functools.partial(self.on_data_changed, download))
|
||||
download.error.connect(self.on_error)
|
||||
|
@ -946,7 +946,8 @@ class HintManager(QObject):
|
||||
elems.label.setInnerXml(string)
|
||||
handler()
|
||||
|
||||
@cmdutils.register(instance='hintmanager', scope='tab', hide=True)
|
||||
@cmdutils.register(instance='hintmanager', scope='tab', hide=True,
|
||||
modes=[usertypes.KeyMode.hint])
|
||||
def follow_hint(self, keystring=None):
|
||||
"""Follow a hint.
|
||||
|
||||
@ -958,6 +959,8 @@ class HintManager(QObject):
|
||||
raise cmdexc.CommandError("No hint to follow")
|
||||
else:
|
||||
keystring = self._context.to_follow
|
||||
elif keystring not in self._context.elems:
|
||||
raise cmdexc.CommandError("No hint {}!".format(keystring))
|
||||
self.fire(keystring, force=True)
|
||||
|
||||
@pyqtSlot('QSize')
|
||||
|
@ -360,17 +360,21 @@ class NetworkManager(QNetworkAccessManager):
|
||||
req.setRawHeader('DNT'.encode('ascii'), dnt)
|
||||
req.setRawHeader('X-Do-Not-Track'.encode('ascii'), dnt)
|
||||
|
||||
if self._tab_id is None:
|
||||
current_url = QUrl() # generic NetworkManager, e.g. for downloads
|
||||
else:
|
||||
# There are some scenarios where we can't figure out current_url:
|
||||
# - There's a generic NetworkManager, e.g. for downloads
|
||||
# - The download was in a tab which is now closed.
|
||||
current_url = QUrl()
|
||||
|
||||
if self._tab_id is not None:
|
||||
try:
|
||||
webview = objreg.get('webview', scope='tab',
|
||||
window=self._win_id, tab=self._tab_id)
|
||||
except KeyError:
|
||||
# https://github.com/The-Compiler/qutebrowser/issues/889
|
||||
current_url = QUrl()
|
||||
else:
|
||||
current_url = webview.url()
|
||||
except (KeyError, RuntimeError, TypeError):
|
||||
# https://github.com/The-Compiler/qutebrowser/issues/889
|
||||
# Catching RuntimeError and TypeError because we could be in
|
||||
# the middle of the webpage shutdown here.
|
||||
current_url = QUrl()
|
||||
|
||||
self.set_referer(req, current_url)
|
||||
|
||||
|
@ -292,7 +292,7 @@ class WebView(QWebView):
|
||||
try:
|
||||
elem = webelem.focus_elem(self.page().currentFrame())
|
||||
except (webelem.IsNullError, RuntimeError):
|
||||
log.mouse.warning("Element/page vanished!")
|
||||
log.mouse.debug("Element/page vanished!")
|
||||
return
|
||||
if elem.is_editable():
|
||||
log.mouse.debug("Clicked editable element (delayed)!")
|
||||
|
@ -29,6 +29,7 @@ import sys
|
||||
import os.path
|
||||
import functools
|
||||
import configparser
|
||||
import contextlib
|
||||
import collections
|
||||
import collections.abc
|
||||
|
||||
@ -666,6 +667,18 @@ class ConfigManager(QObject):
|
||||
newval = val.typ.transform(newval)
|
||||
return newval
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _handle_config_error(self):
|
||||
"""Catch errors in set_command and raise CommandError."""
|
||||
try:
|
||||
yield
|
||||
except (configexc.NoOptionError, configexc.NoSectionError,
|
||||
configexc.ValidationError) as e:
|
||||
raise cmdexc.CommandError("set: {}".format(e))
|
||||
except (configexc.Error, configparser.Error) as e:
|
||||
raise cmdexc.CommandError("set: {} - {}".format(
|
||||
e.__class__.__name__, e))
|
||||
|
||||
@cmdutils.register(name='set', instance='config', win_id='win_id',
|
||||
completion=[Completion.section, Completion.option,
|
||||
Completion.value])
|
||||
@ -699,12 +712,12 @@ class ConfigManager(QObject):
|
||||
tabbed_browser.openurl(QUrl('qute:settings'), newtab=False)
|
||||
return
|
||||
|
||||
if option.endswith('?'):
|
||||
if option.endswith('?') and option != '?':
|
||||
option = option[:-1]
|
||||
print_ = True
|
||||
else:
|
||||
try:
|
||||
if option.endswith('!') and value is None:
|
||||
with self._handle_config_error():
|
||||
if option.endswith('!') and option != '!' and value is None:
|
||||
option = option[:-1]
|
||||
val = self.get(section_, option)
|
||||
layer = 'temp' if temp else 'conf'
|
||||
@ -719,12 +732,10 @@ class ConfigManager(QObject):
|
||||
else:
|
||||
raise cmdexc.CommandError("set: The following arguments "
|
||||
"are required: value")
|
||||
except (configexc.Error, configparser.Error) as e:
|
||||
raise cmdexc.CommandError("set: {} - {}".format(
|
||||
e.__class__.__name__, e))
|
||||
|
||||
if print_:
|
||||
val = self.get(section_, option, transformed=False)
|
||||
with self._handle_config_error():
|
||||
val = self.get(section_, option, transformed=False)
|
||||
message.info(win_id, "{} {} = {}".format(
|
||||
section_, option, val), immediately=True)
|
||||
|
||||
|
@ -92,7 +92,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
|
||||
@cmdutils.register(instance='status-command', name='set-cmd-text',
|
||||
scope='window', maxsplit=0)
|
||||
def set_cmd_text_command(self, text, space=False):
|
||||
def set_cmd_text_command(self, text, space=False, append=False):
|
||||
"""Preset the statusbar to some text.
|
||||
|
||||
//
|
||||
@ -103,6 +103,7 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
Args:
|
||||
text: The commandline to set.
|
||||
space: If given, a space is added to the end.
|
||||
append: If given, the text is appended to the current text.
|
||||
"""
|
||||
tabbed_browser = objreg.get('tabbed-browser', scope='window',
|
||||
window=self._win_id)
|
||||
@ -122,8 +123,14 @@ class Command(misc.MinimalLineEditMixin, misc.CommandLineEdit):
|
||||
# I'm not sure what's the best thing to do here
|
||||
# https://github.com/The-Compiler/qutebrowser/issues/123
|
||||
text = text.replace('{url}', url)
|
||||
|
||||
if space:
|
||||
text += ' '
|
||||
if append:
|
||||
if not self.text():
|
||||
raise cmdexc.CommandError("No current text!")
|
||||
text = self.text() + text
|
||||
|
||||
if not text or text[0] not in modeparsers.STARTCHARS:
|
||||
raise cmdexc.CommandError(
|
||||
"Invalid command text '{}'.".format(text))
|
||||
|
@ -82,7 +82,7 @@ class ExternalEditor(QObject):
|
||||
encoding = config.get('general', 'editor-encoding')
|
||||
try:
|
||||
with open(self._filename, 'r', encoding=encoding) as f:
|
||||
text = ''.join(f.readlines()) # pragma: no branch
|
||||
text = f.read() # pragma: no branch
|
||||
except OSError as e:
|
||||
# NOTE: Do not replace this with "raise CommandError" as it's
|
||||
# executed async.
|
||||
|
@ -213,9 +213,9 @@ class LineParser(BaseLineParser):
|
||||
"""Read the data from self._configfile."""
|
||||
with self._open('r') as f:
|
||||
if self._binary:
|
||||
self.data = [line.rstrip(b'\n') for line in f.readlines()]
|
||||
self.data = [line.rstrip(b'\n') for line in f]
|
||||
else:
|
||||
self.data = [line.rstrip('\n') for line in f.readlines()]
|
||||
self.data = [line.rstrip('\n') for line in f]
|
||||
|
||||
def save(self):
|
||||
"""Save the config file."""
|
||||
|
@ -320,10 +320,14 @@ def qt_message_handler(msg_type, context, msg):
|
||||
level = logging.DEBUG
|
||||
else:
|
||||
level = qt_to_logging[msg_type]
|
||||
|
||||
if context.function is None:
|
||||
func = 'none'
|
||||
elif ':' in context.function:
|
||||
func = '"{}"'.format(context.function)
|
||||
else:
|
||||
func = context.function
|
||||
|
||||
if context.category is None or context.category == 'default':
|
||||
name = 'qt'
|
||||
else:
|
||||
|
@ -112,7 +112,7 @@ def _release_info():
|
||||
for fn in glob.glob("/etc/*-release"):
|
||||
try:
|
||||
with open(fn, 'r', encoding='utf-8') as f:
|
||||
data.append((fn, ''.join(f.readlines()))) # pragma: no branch
|
||||
data.append((fn, f.read())) # pragma: no branch
|
||||
except OSError:
|
||||
log.misc.exception("Error while reading {}.".format(fn))
|
||||
return data
|
||||
|
@ -48,6 +48,8 @@ PERFECT_FILES = [
|
||||
('tests/unit/commands/test_argparser.py',
|
||||
'qutebrowser/commands/argparser.py'),
|
||||
|
||||
('tests/unit/browser/test_cache.py',
|
||||
'qutebrowser/browser/cache.py'),
|
||||
('tests/unit/browser/test_cookies.py',
|
||||
'qutebrowser/browser/cookies.py'),
|
||||
('tests/unit/browser/test_tabhistory.py',
|
||||
@ -248,9 +250,9 @@ def main():
|
||||
"""
|
||||
utils.change_cwd()
|
||||
if '--check-all' in sys.argv:
|
||||
main_check_all()
|
||||
return main_check_all()
|
||||
else:
|
||||
main_check()
|
||||
return main_check()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -29,6 +29,7 @@ from helpers import utils # pylint: disable=import-error
|
||||
({'a': [1, 2, 3]}, {'a': [1]}),
|
||||
({'a': [1, 2, 3]}, {'a': [..., 2]}),
|
||||
(1.0, 1.00000001),
|
||||
("foobarbaz", "foo*baz"),
|
||||
])
|
||||
def test_partial_compare_equal(val1, val2):
|
||||
assert utils.partial_compare(val1, val2)
|
||||
@ -43,6 +44,7 @@ def test_partial_compare_equal(val1, val2):
|
||||
([1], {1: 2}),
|
||||
({1: 1}, {1: [1]}),
|
||||
({'a': [1, 2, 3]}, {'a': [..., 3]}),
|
||||
("foo*baz", "foobarbaz"),
|
||||
])
|
||||
def test_partial_compare_not_equal(val1, val2):
|
||||
assert not utils.partial_compare(val1, val2)
|
||||
|
@ -20,6 +20,9 @@
|
||||
"""Partial comparison of dicts/lists."""
|
||||
|
||||
|
||||
import fnmatch
|
||||
|
||||
|
||||
def _partial_compare_dict(val1, val2):
|
||||
for key in val2:
|
||||
if key not in val1:
|
||||
@ -71,6 +74,9 @@ def partial_compare(val1, val2):
|
||||
elif isinstance(val2, float):
|
||||
print("Doing float comparison")
|
||||
equal = abs(val1 - val2) < 0.00001
|
||||
elif isinstance(val2, str):
|
||||
print("Doing string comparison")
|
||||
equal = fnmatch.fnmatchcase(val1, val2)
|
||||
else:
|
||||
print("Comparing via ==")
|
||||
equal = val1 == val2
|
||||
|
1
tests/integration/data/downloads/mhtml/simple/requests
Normal file
1
tests/integration/data/downloads/mhtml/simple/requests
Normal file
@ -0,0 +1 @@
|
||||
simple.html
|
10
tests/integration/data/downloads/mhtml/simple/simple.html
Normal file
10
tests/integration/data/downloads/mhtml/simple/simple.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Simple MHTML test</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/">normal link to another page</a>
|
||||
</body>
|
||||
</html>
|
20
tests/integration/data/downloads/mhtml/simple/simple.mht
Normal file
20
tests/integration/data/downloads/mhtml/simple/simple.mht
Normal file
@ -0,0 +1,20 @@
|
||||
Content-Type: multipart/related; boundary="---=_qute-6d584056-b1e4-4882-91e6-d4a6d23adb67"
|
||||
MIME-Version: 1.0
|
||||
|
||||
-----=_qute-6d584056-b1e4-4882-91e6-d4a6d23adb67
|
||||
Content-Location: http://localhost:1234/data/downloads/mhtml/simple/simple.html
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/html; charset="UTF-8"
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
<!DOCTYPE=20html><html><head>
|
||||
=20=20=20=20=20=20=20=20<meta=20charset=3D"utf-8">
|
||||
=20=20=20=20=20=20=20=20<title>Simple=20MHTML=20test</title>
|
||||
=20=20=20=20</head>
|
||||
=20=20=20=20<body>
|
||||
=20=20=20=20=20=20=20=20<a=20href=3D"/">normal=20link=20to=20another=20page=
|
||||
</a>
|
||||
=20=20=20=20
|
||||
|
||||
</body></html>
|
||||
-----=_qute-6d584056-b1e4-4882-91e6-d4a6d23adb67--
|
10
tests/integration/data/hints/link.html
Normal file
10
tests/integration/data/hints/link.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>A link to use hints on</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/data/hello.txt">Follow me!</a>
|
||||
</body>
|
||||
</html>
|
@ -4,6 +4,7 @@ Feature: Going back and forward.
|
||||
Scenario: Going back/forward
|
||||
Given I open data/backforward/1.txt
|
||||
When I open data/backforward/2.txt
|
||||
And I run :tab-only
|
||||
And I run :back
|
||||
And I wait until data/backforward/1.txt is loaded
|
||||
And I reload
|
||||
@ -15,13 +16,81 @@ Feature: Going back and forward.
|
||||
data/backforward/2.txt
|
||||
data/backforward/1.txt
|
||||
data/backforward/2.txt
|
||||
And the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/backforward/1.txt
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/2.txt
|
||||
|
||||
Scenario: Going back without history
|
||||
Given I open data/backforward/1.txt
|
||||
When I run :back
|
||||
Then the error "At beginning of history." should be shown.
|
||||
Scenario: Going back in a new tab
|
||||
Given I open data/backforward/1.txt
|
||||
When I open data/backforward/2.txt
|
||||
And I run :tab-only
|
||||
And I run :back -t
|
||||
And I wait until data/backforward/1.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- history:
|
||||
- url: http://localhost:*/data/backforward/1.txt
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/2.txt
|
||||
- active: true
|
||||
history:
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/1.txt
|
||||
- url: http://localhost:*/data/backforward/2.txt
|
||||
|
||||
Scenario: Going forward without history
|
||||
Given I open data/backforward/1.txt
|
||||
When I run :forward
|
||||
Then the error "At end of history." should be shown.
|
||||
Scenario: Going back in a new background tab
|
||||
Given I open data/backforward/1.txt
|
||||
When I open data/backforward/2.txt
|
||||
And I run :tab-only
|
||||
And I run :back -b
|
||||
And I wait until data/backforward/1.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- active: true
|
||||
history:
|
||||
- url: http://localhost:*/data/backforward/1.txt
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/2.txt
|
||||
- history:
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/1.txt
|
||||
- url: http://localhost:*/data/backforward/2.txt
|
||||
|
||||
Scenario: Going back in a new window
|
||||
Given I have a fresh instance
|
||||
When I open data/backforward/1.txt
|
||||
And I open data/backforward/2.txt
|
||||
And I run :back -w
|
||||
And I wait until data/backforward/1.txt is loaded
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- active: true
|
||||
history:
|
||||
- url: about:blank
|
||||
- url: http://localhost:*/data/backforward/1.txt
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/2.txt
|
||||
- tabs:
|
||||
- active: true
|
||||
history:
|
||||
- url: about:blank
|
||||
- active: true
|
||||
url: http://localhost:*/data/backforward/1.txt
|
||||
- url: http://localhost:*/data/backforward/2.txt
|
||||
|
||||
Scenario: Going back without history
|
||||
Given I open data/backforward/1.txt
|
||||
When I run :back
|
||||
Then the error "At beginning of history." should be shown.
|
||||
|
||||
Scenario: Going forward without history
|
||||
Given I open data/backforward/1.txt
|
||||
When I run :forward
|
||||
Then the error "At end of history." should be shown.
|
||||
|
@ -53,6 +53,13 @@ def run_command_given(quteproc, command):
|
||||
quteproc.send_cmd(command)
|
||||
|
||||
|
||||
@bdd.given("I have a fresh instance")
|
||||
def fresh_instance(quteproc):
|
||||
"""Restart qutebrowser instance for tests needing a fresh state."""
|
||||
quteproc.terminate()
|
||||
quteproc.start()
|
||||
|
||||
|
||||
@bdd.when(bdd.parsers.parse("I run {command}"))
|
||||
def run_command_when(quteproc, httpbin, command):
|
||||
command = command.replace('(port)', str(httpbin.port))
|
||||
|
20
tests/integration/features/hints.feature
Normal file
20
tests/integration/features/hints.feature
Normal file
@ -0,0 +1,20 @@
|
||||
Feature: Using hints
|
||||
|
||||
Scenario: Following a hint.
|
||||
When I open data/hints/link.html
|
||||
And I run :hint links normal
|
||||
And I run :follow-hint a
|
||||
And I wait until data/hello.txt is loaded
|
||||
Then the requests should be:
|
||||
data/hints/link.html
|
||||
data/hello.txt
|
||||
|
||||
Scenario: Using :follow-hint outside of hint mode (issue 1105)
|
||||
When I run :follow-hint
|
||||
Then the error "follow-hint: This command is only allowed in hint mode." should be shown.
|
||||
|
||||
Scenario: Using :follow-hint with an invalid index.
|
||||
When I open data/hints/link.html
|
||||
And I run :hint links normal
|
||||
And I run :follow-hint xyz
|
||||
Then the error "No hint xyz!" should be shown.
|
44
tests/integration/features/misc.feature
Normal file
44
tests/integration/features/misc.feature
Normal file
@ -0,0 +1,44 @@
|
||||
Feature: Various utility commands.
|
||||
|
||||
Scenario: :set-cmd-text and :command-accept
|
||||
When I run :set-cmd-text :message-info "Hello World"
|
||||
And I run :command-accept
|
||||
Then the message "Hello World" should be shown.
|
||||
|
||||
Scenario: :set-cmd-text with two commands
|
||||
When I run :set-cmd-text :message-info test ;; message-error error
|
||||
And I run :command-accept
|
||||
Then the message "test" should be shown.
|
||||
And the error "error" should be shown.
|
||||
|
||||
Scenario: :set-cmd-text with URL replacement
|
||||
When I open data/hello.txt
|
||||
When I run :set-cmd-text :message-info >{url}<
|
||||
And I run :command-accept
|
||||
Then the message ">http://localhost:*/hello.txt<" should be shown.
|
||||
|
||||
Scenario: :set-cmd-text with -s and -a
|
||||
When I run :set-cmd-text -s :message-info "foo
|
||||
And I run :set-cmd-text -a bar"
|
||||
And I run :command-accept
|
||||
Then the message "foo bar" should be shown.
|
||||
|
||||
Scenario: :set-cmd-text with -a but without text
|
||||
When I run :set-cmd-text -a foo
|
||||
Then the error "No current text!" should be shown.
|
||||
|
||||
Scenario: :set-cmd-text with invalid command
|
||||
When I run :set-cmd-text foo
|
||||
Then the error "Invalid command text 'foo'." should be shown.
|
||||
|
||||
Scenario: :message-error
|
||||
When I run :message-error "Hello World"
|
||||
Then the error "Hello World" should be shown.
|
||||
|
||||
Scenario: :message-info
|
||||
When I run :message-info "Hello World"
|
||||
Then the message "Hello World" should be shown.
|
||||
|
||||
Scenario: :message-warning
|
||||
When I run :message-warning "Hello World"
|
||||
Then the warning "Hello World" should be shown.
|
101
tests/integration/features/set.feature
Normal file
101
tests/integration/features/set.feature
Normal file
@ -0,0 +1,101 @@
|
||||
Feature: Setting settings.
|
||||
|
||||
Background:
|
||||
Given I set ui -> message-timeout to 100
|
||||
|
||||
Scenario: Using :set
|
||||
When I run :set colors statusbar.bg magenta
|
||||
Then colors -> statusbar.bg should be magenta
|
||||
|
||||
Scenario: Only a section
|
||||
When I run :set colors
|
||||
Then the error "set: Either both section and option have to be given, or neither!" should be shown.
|
||||
|
||||
Scenario: Without value
|
||||
When I run :set colors statusbar.bg
|
||||
Then the error "set: The following arguments are required: value" should be shown.
|
||||
|
||||
Scenario: Invalid section
|
||||
When I run :set blah blub foo
|
||||
Then the error "set: Section 'blah' does not exist!" should be shown.
|
||||
|
||||
Scenario: Invalid option
|
||||
When I run :set general blub foo
|
||||
Then the error "set: No option 'blub' in section 'general'" should be shown.
|
||||
|
||||
Scenario: Toggling an option
|
||||
When I run :set general auto-save-config false
|
||||
And I run :set general auto-save-config!
|
||||
Then general -> auto-save-config should be True
|
||||
|
||||
Scenario: Toggling a non-bool option
|
||||
When I run :set colors statusbar.bg!
|
||||
Then the error "set: Attempted inversion of non-boolean value." should be shown.
|
||||
|
||||
Scenario: Getting an option
|
||||
When I run :set colors statusbar.bg magenta
|
||||
And I run :set colors statusbar.bg?
|
||||
Then the message "colors statusbar.bg = magenta" should be shown.
|
||||
|
||||
Scenario: Using -p
|
||||
When I run :set -p colors statusbar.bg red
|
||||
Then the message "colors statusbar.bg = red" should be shown.
|
||||
|
||||
Scenario: Using ! and -p
|
||||
When I run :set general auto-save-config false
|
||||
And I run :set -p general auto-save-config!
|
||||
Then the message "general auto-save-config = True" should be shown.
|
||||
|
||||
Scenario: Setting an invalid value
|
||||
When I run :set general auto-save-config blah
|
||||
Then the error "set: Invalid value 'blah' - must be a boolean!" should be shown.
|
||||
|
||||
Scenario: Setting a temporary option
|
||||
# We don't actually check if the option is temporary as this isn't easy
|
||||
# to check.
|
||||
When I run :set -t colors statusbar.bg green
|
||||
Then colors -> statusbar.bg should be green
|
||||
|
||||
Scenario: Opening qute:settings
|
||||
When I run :set
|
||||
And I wait for "load status for <qutebrowser.browser.webview.WebView tab_id=0 url='qute:settings'>: LoadStatus.success" in the log
|
||||
Then the session should look like:
|
||||
windows:
|
||||
- tabs:
|
||||
- active: true
|
||||
history:
|
||||
- url: about:blank
|
||||
- active: true
|
||||
url: qute:settings
|
||||
|
||||
Scenario: Empty option with ? (issue 1109)
|
||||
When I run :set general ?
|
||||
Then the error "set: The following arguments are required: value" should be shown.
|
||||
|
||||
Scenario: Invalid section and empty option with ? (issue 1109)
|
||||
When I run :set blah ?
|
||||
Then the error "set: The following arguments are required: value" should be shown.
|
||||
|
||||
Scenario: Invalid option with ? (issue 1109)
|
||||
When I run :set general foo?
|
||||
Then the error "set: No option 'foo' in section 'general'" should be shown.
|
||||
|
||||
Scenario: Invalid section/option with ? (issue 1109)
|
||||
When I run :set blah foo ?
|
||||
Then the error "set: Section 'blah' does not exist!" should be shown.
|
||||
|
||||
Scenario: Empty option with !
|
||||
When I run :set general !
|
||||
Then the error "set: The following arguments are required: value" should be shown.
|
||||
|
||||
Scenario: Invalid section and empty option with !
|
||||
When I run :set blah !
|
||||
Then the error "set: The following arguments are required: value" should be shown.
|
||||
|
||||
Scenario: Invalid option with !
|
||||
When I run :set general foo!
|
||||
Then the error "set: No option 'foo' in section 'general'" should be shown.
|
||||
|
||||
Scenario: Invalid section/option with !
|
||||
When I run :set blah foo !
|
||||
Then the error "set: Section 'blah' does not exist!" should be shown.
|
21
tests/integration/features/test_hints.py
Normal file
21
tests/integration/features/test_hints.py
Normal file
@ -0,0 +1,21 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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_bdd as bdd
|
||||
bdd.scenarios('hints.feature')
|
21
tests/integration/features/test_misc.py
Normal file
21
tests/integration/features/test_misc.py
Normal file
@ -0,0 +1,21 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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_bdd as bdd
|
||||
bdd.scenarios('misc.feature')
|
32
tests/integration/features/test_set.py
Normal file
32
tests/integration/features/test_set.py
Normal file
@ -0,0 +1,32 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
import pytest_bdd as bdd
|
||||
bdd.scenarios('set.feature')
|
||||
|
||||
|
||||
@bdd.then(bdd.parsers.parse("{section} -> {option} should be {value}"))
|
||||
def check_option(quteproc, section, option, value):
|
||||
quteproc.send_cmd(':set {} {}?'.format(section, option))
|
||||
msg = quteproc.wait_for(loglevel=logging.INFO, category='message',
|
||||
message='{} {} = *'.format(section, option))
|
||||
actual_value = msg.message.split(' = ')[1]
|
||||
assert actual_value == value
|
@ -68,7 +68,9 @@ class LogLine(testprocess.Line):
|
||||
(?P<timestamp>\d\d:\d\d:\d\d)
|
||||
\ (?P<loglevel>VDEBUG|DEBUG|INFO|WARNING|ERROR)
|
||||
\ +(?P<category>\w+)
|
||||
\ +(?P<module>(\w+|Unknown\ module)):(?P<function>\w+):(?P<line>\d+)
|
||||
\ +(?P<module>(\w+|Unknown\ module)):
|
||||
(?P<function>[^"][^:]*|"[^"]+"):
|
||||
(?P<line>\d+)
|
||||
\ (?P<message>.+)
|
||||
""", re.VERBOSE)
|
||||
|
||||
@ -94,9 +96,22 @@ class LogLine(testprocess.Line):
|
||||
else:
|
||||
self.module = module
|
||||
|
||||
self.function = match.group('function')
|
||||
self.line = int(match.group('line'))
|
||||
self.message = match.group('message')
|
||||
function = match.group('function')
|
||||
if function == 'none':
|
||||
self.function = None
|
||||
else:
|
||||
self.function = function.strip('"')
|
||||
|
||||
line = int(match.group('line'))
|
||||
if self.function is None and line == 0:
|
||||
self.line = None
|
||||
else:
|
||||
self.line = line
|
||||
|
||||
msg_match = re.match(r'^(\[(?P<prefix>\d+s ago)\] )?(?P<message>.*)',
|
||||
match.group('message'))
|
||||
self.prefix = msg_match.group('prefix')
|
||||
self.message = msg_match.group('message')
|
||||
|
||||
self.expected = is_ignored_qt_message(self.message)
|
||||
|
||||
@ -177,7 +192,7 @@ class QuteProc(testprocess.Process):
|
||||
ipc.send_to_running_instance(self._ipc_socket, [command],
|
||||
target_arg='')
|
||||
self.wait_for(category='commands', module='command', function='run',
|
||||
message='Calling *')
|
||||
message='command called: *')
|
||||
|
||||
def set_setting(self, sect, opt, value):
|
||||
self.send_cmd(':set "{}" "{}" "{}"'.format(sect, opt, value))
|
||||
@ -197,7 +212,7 @@ class QuteProc(testprocess.Process):
|
||||
message=message)
|
||||
line.expected = True
|
||||
|
||||
def wait_for(self, timeout=15000, **kwargs):
|
||||
def wait_for(self, timeout=None, **kwargs):
|
||||
"""Override testprocess.wait_for to check past messages.
|
||||
|
||||
self._data is cleared after every test to provide at least some
|
||||
|
103
tests/integration/test_mhtml_e2e.py
Normal file
103
tests/integration/test_mhtml_e2e.py
Normal file
@ -0,0 +1,103 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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 mhtml downloads based on sample files."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import os.path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def collect_tests():
|
||||
basedir = os.path.dirname(__file__)
|
||||
datadir = os.path.join(basedir, 'data', 'downloads', 'mhtml')
|
||||
files = os.listdir(datadir)
|
||||
return files
|
||||
|
||||
|
||||
def normalize_line(line):
|
||||
line = line.rstrip('\n')
|
||||
line = re.sub('boundary="---=_qute-[0-9a-f-]+"',
|
||||
'boundary="---=_qute-UUID"', line)
|
||||
line = re.sub('^-----=_qute-[0-9a-f-]+$', '-----=_qute-UUID', line)
|
||||
line = re.sub(r'localhost:\d{1,5}', 'localhost:(port)', line)
|
||||
return line
|
||||
|
||||
|
||||
class DownloadDir:
|
||||
|
||||
"""Abstraction over a download directory."""
|
||||
|
||||
def __init__(self, tmpdir):
|
||||
self._tmpdir = tmpdir
|
||||
self.location = str(tmpdir)
|
||||
|
||||
def read_file(self):
|
||||
files = self._tmpdir.listdir()
|
||||
assert len(files) == 1
|
||||
|
||||
with open(str(files[0]), 'r', encoding='utf-8') as f:
|
||||
return f.readlines()
|
||||
|
||||
def compare_mhtml(self, filename):
|
||||
with open(filename, 'r', encoding='utf-8') as f:
|
||||
expected_data = [normalize_line(line) for line in f]
|
||||
actual_data = self.read_file()
|
||||
actual_data = [normalize_line(line) for line in actual_data]
|
||||
assert actual_data == expected_data
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def download_dir(tmpdir):
|
||||
return DownloadDir(tmpdir)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('test_name', collect_tests())
|
||||
def test_mhtml(test_name, download_dir, quteproc, httpbin):
|
||||
quteproc.set_setting('storage', 'download-directory',
|
||||
download_dir.location)
|
||||
quteproc.set_setting('storage', 'prompt-download-directory', 'false')
|
||||
|
||||
test_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
||||
'data', 'downloads', 'mhtml', test_name)
|
||||
test_path = 'data/downloads/mhtml/{}'.format(test_name)
|
||||
|
||||
quteproc.open_path('{}/{}.html'.format(test_path, test_name))
|
||||
download_dest = os.path.join(download_dir.location,
|
||||
'{}-downloaded.mht'.format(test_name))
|
||||
quteproc.send_cmd(':download --mhtml --dest "{}"'.format(download_dest))
|
||||
quteproc.wait_for(category='downloads', module='mhtml',
|
||||
function='finish_file',
|
||||
message='All assets downloaded, ready to finish off!')
|
||||
|
||||
expected_file = os.path.join(test_dir, '{}.mht'.format(test_name))
|
||||
download_dir.compare_mhtml(expected_file)
|
||||
|
||||
with open(os.path.join(test_dir, 'requests'), encoding='utf-8') as f:
|
||||
expected_requests = []
|
||||
for line in f:
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
path = '/{}/{}'.format(test_path, line.strip())
|
||||
expected_requests.append(httpbin.Request('GET', path))
|
||||
|
||||
actual_requests = httpbin.get_requests()
|
||||
assert sorted(actual_requests) == sorted(expected_requests)
|
@ -19,8 +19,14 @@
|
||||
|
||||
"""Test the quteproc fixture used for tests."""
|
||||
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import quteprocess
|
||||
from qutebrowser.utils import log
|
||||
|
||||
|
||||
def test_quteproc_error_message(qtbot, quteproc):
|
||||
"""Make sure the test fails with an unexpected error message."""
|
||||
@ -36,3 +42,76 @@ def test_qt_log_ignore(qtbot, quteproc):
|
||||
"""Make sure the test passes when logging a qt_log_ignore message."""
|
||||
with qtbot.waitSignal(quteproc.got_error, raising=True):
|
||||
quteproc.send_cmd(':message-error "SpellCheck: test"')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('data, attrs', [
|
||||
(
|
||||
# Normal message
|
||||
'01:02:03 DEBUG init earlyinit:init_log:280 Log initialized.',
|
||||
{
|
||||
'timestamp': datetime.datetime(year=1900, month=1, day=1,
|
||||
hour=1, minute=2, second=3),
|
||||
'loglevel': logging.DEBUG,
|
||||
'category': 'init',
|
||||
'module': 'earlyinit',
|
||||
'function': 'init_log',
|
||||
'line': 280,
|
||||
'message': 'Log initialized.',
|
||||
'expected': False,
|
||||
}
|
||||
),
|
||||
(
|
||||
# VDEBUG
|
||||
'00:00:00 VDEBUG foo foo:foo:0 test',
|
||||
{'loglevel': log.VDEBUG_LEVEL}
|
||||
),
|
||||
(
|
||||
# Unknown module
|
||||
'00:00:00 WARNING qt Unknown module:none:0 test',
|
||||
{'module': None, 'function': None, 'line': None},
|
||||
),
|
||||
(
|
||||
# Expected message
|
||||
'00:00:00 VDEBUG foo foo:foo:0 SpellCheck: test',
|
||||
{'expected': True},
|
||||
),
|
||||
(
|
||||
# Weird Qt location
|
||||
'00:00:00 DEBUG qt qnetworkreplyhttpimpl:"void '
|
||||
'QNetworkReplyHttpImplPrivate::error(QNetworkReply::NetworkError, '
|
||||
'const QString&)":1929 QNetworkReplyImplPrivate::error: Internal '
|
||||
'problem, this method must only be called once.',
|
||||
{
|
||||
'module': 'qnetworkreplyhttpimpl',
|
||||
'function': 'void QNetworkReplyHttpImplPrivate::error('
|
||||
'QNetworkReply::NetworkError, const QString&)',
|
||||
'line': 1929
|
||||
}
|
||||
),
|
||||
(
|
||||
'00:00:00 WARNING qt qxcbxsettings:"QXcbXSettings::'
|
||||
'QXcbXSettings(QXcbScreen*)":233 '
|
||||
'QXcbXSettings::QXcbXSettings(QXcbScreen*) Failed to get selection '
|
||||
'owner for XSETTINGS_S atom ',
|
||||
{
|
||||
'module': 'qxcbxsettings',
|
||||
'function': 'QXcbXSettings::QXcbXSettings(QXcbScreen*)',
|
||||
'line': 233,
|
||||
}
|
||||
),
|
||||
(
|
||||
# With [2s ago] marker
|
||||
'00:00:00 DEBUG foo foo:foo:0 [2s ago] test',
|
||||
{'prefix': '2s ago', 'message': 'test'}
|
||||
),
|
||||
])
|
||||
def test_log_line_parse(data, attrs):
|
||||
line = quteprocess.LogLine(data)
|
||||
for name, expected in attrs.items():
|
||||
actual = getattr(line, name)
|
||||
assert actual == expected, name
|
||||
|
||||
|
||||
def test_log_line_no_match():
|
||||
with pytest.raises(quteprocess.NoLineMatch):
|
||||
quteprocess.LogLine("Hello World!")
|
||||
|
@ -20,6 +20,7 @@
|
||||
"""Base class for a subprocess run for tests.."""
|
||||
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
import fnmatch
|
||||
|
||||
@ -136,7 +137,9 @@ class Process(QObject):
|
||||
print("INVALID: {}".format(line))
|
||||
continue
|
||||
|
||||
if parsed is not None:
|
||||
if parsed is None:
|
||||
print("IGNORED: {}".format(line))
|
||||
else:
|
||||
self._data.append(parsed)
|
||||
self.new_data.emit(parsed)
|
||||
|
||||
@ -213,7 +216,7 @@ class Process(QObject):
|
||||
else:
|
||||
return value == expected
|
||||
|
||||
def wait_for(self, timeout=15000, **kwargs):
|
||||
def wait_for(self, timeout=None, **kwargs):
|
||||
"""Wait until a given value is found in the data.
|
||||
|
||||
Keyword arguments to this function get interpreted as attributes of the
|
||||
@ -223,6 +226,11 @@ class Process(QObject):
|
||||
Return:
|
||||
The matched line.
|
||||
"""
|
||||
if timeout is None:
|
||||
if 'CI' in os.environ:
|
||||
timeout = 15000
|
||||
else:
|
||||
timeout = 5000
|
||||
# Search existing messages
|
||||
for line in self._data:
|
||||
matches = []
|
||||
|
@ -35,6 +35,55 @@ def preload_cache(cache, url='http://www.example.com/', content=b'foobar'):
|
||||
cache.insert(device)
|
||||
|
||||
|
||||
def test_cache_config_change_cache_size(config_stub, tmpdir):
|
||||
"""Change cache size and emit signal to trigger on_config_changed."""
|
||||
max_cache_size = 1024
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': max_cache_size},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.maximumCacheSize() == max_cache_size
|
||||
|
||||
config_stub.set('storage', 'cache-size', max_cache_size * 2)
|
||||
assert disk_cache.maximumCacheSize() == max_cache_size * 2
|
||||
|
||||
|
||||
def test_cache_config_enable_private_browsing(config_stub, tmpdir):
|
||||
"""Change private-browsing config to True and emit signal."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.cacheSize() == 0
|
||||
preload_cache(disk_cache)
|
||||
assert disk_cache.cacheSize() > 0
|
||||
|
||||
config_stub.set('general', 'private-browsing', True)
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_config_disable_private_browsing(config_stub, tmpdir):
|
||||
"""Change private-browsing config to False and emit signal."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.prepare(metadata) is None
|
||||
|
||||
config_stub.set('general', 'private-browsing', False)
|
||||
content = b'cute'
|
||||
preload_cache(disk_cache, url, content)
|
||||
assert disk_cache.data(QUrl(url)).readAll() == content
|
||||
|
||||
|
||||
def test_cache_size_leq_max_cache_size(config_stub, tmpdir):
|
||||
"""Test cacheSize <= MaximumCacheSize when cache is activated."""
|
||||
limit = 100
|
||||
@ -54,6 +103,63 @@ def test_cache_size_leq_max_cache_size(config_stub, tmpdir):
|
||||
assert disk_cache.cacheSize() < limit+100
|
||||
|
||||
|
||||
def test_cache_size_deactivated(config_stub, tmpdir):
|
||||
"""Confirm that the cache size returns 0 when deactivated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_existing_metadata_file(config_stub, tmpdir):
|
||||
"""Test querying existing meta data file from activated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
content = b'foobar'
|
||||
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
device = disk_cache.prepare(metadata)
|
||||
assert device is not None
|
||||
device.write(content)
|
||||
disk_cache.insert(device)
|
||||
disk_cache.updateMetaData(metadata)
|
||||
|
||||
files = list(tmpdir.visit(fil=lambda path: path.isfile()))
|
||||
assert len(files) == 1
|
||||
assert disk_cache.fileMetaData(str(files[0])) == metadata
|
||||
|
||||
|
||||
def test_cache_nonexistent_metadata_file(config_stub, tmpdir):
|
||||
"""Test querying nonexistent meta data file from activated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
cache_file = disk_cache.fileMetaData("nosuchfile")
|
||||
assert cache_file.isValid() == False
|
||||
|
||||
|
||||
def test_cache_deactivated_metadata_file(config_stub, tmpdir):
|
||||
"""Test querying meta data file when cache is deactivated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.fileMetaData("foo") == QNetworkCacheMetaData()
|
||||
|
||||
|
||||
def test_cache_deactivated_private_browsing(config_stub, tmpdir):
|
||||
"""Test if cache is deactivated in private-browsing mode."""
|
||||
config_stub.data = {
|
||||
@ -104,12 +210,15 @@ def test_cache_deactivated_remove_data(config_stub, tmpdir):
|
||||
assert disk_cache.remove(url) == False
|
||||
|
||||
|
||||
def test_cache_insert_data(tmpdir):
|
||||
def test_cache_insert_data(config_stub, tmpdir):
|
||||
"""Test if entries inserted into the cache are actually there."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
content = b'foobar'
|
||||
disk_cache = QNetworkDiskCache()
|
||||
disk_cache.setCacheDirectory(str(tmpdir))
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
preload_cache(disk_cache, url, content)
|
||||
@ -118,11 +227,37 @@ def test_cache_insert_data(tmpdir):
|
||||
assert disk_cache.data(QUrl(url)).readAll() == content
|
||||
|
||||
|
||||
def test_cache_remove_data(tmpdir):
|
||||
"""Test if a previously inserted entry can be removed from the cache."""
|
||||
def test_cache_deactivated_insert_data(config_stub, tmpdir):
|
||||
"""Insert data when cache is deactivated."""
|
||||
# First create QNetworkDiskCache just to get a valid QIODevice from it
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = QNetworkDiskCache()
|
||||
disk_cache.setCacheDirectory(str(tmpdir))
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
device = disk_cache.prepare(metadata)
|
||||
assert device is not None
|
||||
|
||||
# Now create a deactivated DiskCache and insert the valid device created
|
||||
# above (there probably is a better way to get a valid QIODevice...)
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
|
||||
deactivated_cache = cache.DiskCache(str(tmpdir))
|
||||
assert deactivated_cache.insert(device) is None
|
||||
|
||||
|
||||
|
||||
def test_cache_remove_data(config_stub, tmpdir):
|
||||
"""Test if a previously inserted entry can be removed from the cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
preload_cache(disk_cache, url)
|
||||
assert disk_cache.cacheSize() > 0
|
||||
|
||||
@ -146,14 +281,27 @@ def test_cache_clear_activated(config_stub, tmpdir):
|
||||
assert disk_cache.cacheSize() == 0
|
||||
|
||||
|
||||
def test_cache_metadata(tmpdir):
|
||||
def test_cache_clear_deactivated(config_stub, tmpdir):
|
||||
"""Test method clear() on deactivated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.clear() is None
|
||||
|
||||
|
||||
def test_cache_metadata(config_stub, tmpdir):
|
||||
"""Ensure that DiskCache.metaData() returns exactly what was inserted."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
disk_cache = QNetworkDiskCache()
|
||||
disk_cache.setCacheDirectory(str(tmpdir))
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
device = disk_cache.prepare(metadata)
|
||||
device.write(b'foobar')
|
||||
disk_cache.insert(device)
|
||||
@ -161,11 +309,26 @@ def test_cache_metadata(tmpdir):
|
||||
assert disk_cache.metaData(QUrl(url)) == metadata
|
||||
|
||||
|
||||
def test_cache_update_metadata(tmpdir):
|
||||
"""Test updating the meta data for an existing cache entry."""
|
||||
def test_cache_deactivated_metadata(config_stub, tmpdir):
|
||||
"""Test querying metaData() on not activated cache."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = QNetworkDiskCache()
|
||||
disk_cache.setCacheDirectory(str(tmpdir))
|
||||
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
assert disk_cache.metaData(QUrl(url)) == QNetworkCacheMetaData()
|
||||
|
||||
|
||||
def test_cache_update_metadata(config_stub, tmpdir):
|
||||
"""Test updating the meta data for an existing cache entry."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': False}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
preload_cache(disk_cache, url, b'foo')
|
||||
assert disk_cache.cacheSize() > 0
|
||||
|
||||
@ -176,6 +339,21 @@ def test_cache_update_metadata(tmpdir):
|
||||
assert disk_cache.metaData(QUrl(url)) == metadata
|
||||
|
||||
|
||||
def test_cache_deactivated_update_metadata(config_stub, tmpdir):
|
||||
"""Test updating the meta data when cache is not activated."""
|
||||
config_stub.data = {
|
||||
'storage': {'cache-size': 1024},
|
||||
'general': {'private-browsing': True}
|
||||
}
|
||||
url = 'http://qutebrowser.org'
|
||||
disk_cache = cache.DiskCache(str(tmpdir))
|
||||
|
||||
metadata = QNetworkCacheMetaData()
|
||||
metadata.setUrl(QUrl(url))
|
||||
assert metadata.isValid()
|
||||
assert disk_cache.updateMetaData(metadata) is None
|
||||
|
||||
|
||||
def test_cache_full(config_stub, tmpdir):
|
||||
"""Do a sanity test involving everything."""
|
||||
config_stub.data = {
|
||||
|
@ -520,11 +520,13 @@ def test_unset_organization(qapp, orgname, expected):
|
||||
assert qapp.organizationName() == expected
|
||||
|
||||
|
||||
if test_file is not None:
|
||||
if test_file is not None and sys.platform != 'darwin':
|
||||
# If we were able to import Python's test_file module, we run some code
|
||||
# here which defines unittest TestCases to run the python tests over
|
||||
# PyQIODevice.
|
||||
|
||||
# Those are not run on OS X because that seems to cause a hang sometimes.
|
||||
|
||||
@pytest.yield_fixture(scope='session', autouse=True)
|
||||
def clean_up_python_testfile():
|
||||
"""Clean up the python testfile after tests if tests didn't."""
|
||||
|
Loading…
Reference in New Issue
Block a user