Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d9e9851f1 | ||
|
|
c1ab3ebc71 | ||
|
|
8376b21f92 | ||
|
|
9a9b0643a5 | ||
|
|
715157a7d0 | ||
|
|
f88036e780 | ||
|
|
aefac1ad19 | ||
|
|
1654bc4448 | ||
|
|
8a3a785c19 | ||
|
|
d615b49e60 | ||
|
|
4a5f243ff0 | ||
|
|
7a33dff986 | ||
|
|
e62a18f8e8 | ||
|
|
83203820ad | ||
|
|
376d7f2986 | ||
|
|
03b5248ce6 | ||
|
|
25cc0534e6 | ||
|
|
6fe89a3800 | ||
|
|
239b25cc8a | ||
|
|
7fc054d12c | ||
|
|
5679649fcf | ||
|
|
2e0f8a22f0 | ||
|
|
b8998e7741 | ||
|
|
2e228703b5 | ||
|
|
8ce7f76b16 | ||
|
|
b603b7e20a | ||
|
|
b9e8aedf8b | ||
|
|
43bab89bdd |
@@ -14,5 +14,4 @@ test_script:
|
||||
- C:\Python34\Scripts\tox -e py34
|
||||
- C:\Python34\Scripts\tox -e py34-integration
|
||||
- C:\Python34\Scripts\tox -e unittests-frozen
|
||||
- C:\Python34\Scripts\tox -e smoke-frozen
|
||||
- C:\Python34\Scripts\tox -e pylint
|
||||
|
||||
30
.travis.yml
30
.travis.yml
@@ -1,4 +1,5 @@
|
||||
dist: trusty
|
||||
# So we get Ubuntu Trusty - using "dist: trusty" breaks OS X.
|
||||
services: docker
|
||||
|
||||
os:
|
||||
- linux
|
||||
@@ -12,22 +13,21 @@ cache:
|
||||
- $HOME/.cache/pip
|
||||
- $HOME/build/The-Compiler/qutebrowser/.cache
|
||||
|
||||
env:
|
||||
- PATH=/home/travis/bin:/home/travis/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
|
||||
install:
|
||||
- python scripts/dev/ci_install.py
|
||||
|
||||
script:
|
||||
- xvfb-run -s "-screen 0 640x480x16" tox -e py34,py34-integration
|
||||
- tox -e misc
|
||||
- tox -e pep257
|
||||
- tox -e pyflakes
|
||||
- tox -e pep8
|
||||
- tox -e mccabe
|
||||
- tox -e pylint
|
||||
- tox -e pyroma
|
||||
- tox -e check-manifest
|
||||
|
||||
# Travis bug - OS X builds get routed to Ubuntu Trusty if "dist: trusty" is
|
||||
# given.
|
||||
matrix:
|
||||
allow_failures:
|
||||
- os: osx
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e unittests-nodisp || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e misc || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e pep257 || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e pyflakes || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e pep8 || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e mccabe || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e pyroma || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e check-manifest || true'
|
||||
- '[[ $TRAVIS_OS_NAME == linux ]] && tox -e pylint || true'
|
||||
|
||||
@@ -14,6 +14,47 @@ This project adheres to http://semver.org/[Semantic Versioning].
|
||||
// `Fixed` for any bug fixes.
|
||||
// `Security` to invite users to upgrade in case of vulnerabilities.
|
||||
|
||||
v0.5.0 (unreleased)
|
||||
-------------------
|
||||
|
||||
Added
|
||||
~~~~~
|
||||
|
||||
- New setting `ui -> hide-wayland-decoration` to hide the window decoration
|
||||
when using wayland.
|
||||
- New userscripts in `misc/userscripts`:
|
||||
- `open_download` to easily open a file in your downloads folder.
|
||||
- `view_in_mpv` to open a video in mpv and remove it from the page.
|
||||
- New setting `content -> host-blocking-whitelist` to whitelist certain domains
|
||||
from the adblocker.
|
||||
|
||||
Changed
|
||||
~~~~~~~
|
||||
|
||||
- The `colors -> tabs.bg/fg.selected` option got split into
|
||||
`tabs.bg/fg.selected.odd/even`.
|
||||
|
||||
v0.4.1
|
||||
------
|
||||
|
||||
Fixed
|
||||
~~~~~
|
||||
|
||||
- Adjusted AppArmor config for the IPC changes in v0.4.0.
|
||||
- Fixed atime update frequency for IPC file.
|
||||
- Worked around a Qt issue where middle-clicking caused scrolling with a
|
||||
touchpad to restart at the beginning of the page.
|
||||
- The `completion -> web-history-max-items` setting is now also respected for
|
||||
items added after starting qutebrowser.
|
||||
- Search terms are now shared between different tabs again
|
||||
- Tests (a reduced subset of them) now run correctly again when DISPLAY is not
|
||||
set.
|
||||
- Fixed an issue causing qutebrowser to crash with Python 3.5 as soon as an ad
|
||||
was blocked.
|
||||
- Fixed an issue causing qutebrowser to not start with more recent Python 3.4
|
||||
versions (e.g. on Debian experimental).
|
||||
- Fixed various `PendingDeprecationWarnings` shown with Python 3.5.
|
||||
|
||||
v0.4.0
|
||||
------
|
||||
|
||||
|
||||
@@ -168,6 +168,7 @@ Contributors, sorted by the number of commits in descending order:
|
||||
* Fritz V155 Reichwald
|
||||
* Franz Fellner
|
||||
* zwarag
|
||||
* neeasade
|
||||
* meles5
|
||||
* error800
|
||||
* Tim Harder
|
||||
|
||||
@@ -29,6 +29,8 @@ profile qutebrowser /usr/{local/,}bin/qutebrowser {
|
||||
|
||||
/proc/*/mounts r,
|
||||
owner /tmp/** rwkl,
|
||||
owner /run/user/*/ rw,
|
||||
owner /run/user/*/** krw,
|
||||
|
||||
@{HOME}/.config/qutebrowser/** krw,
|
||||
@{HOME}/.local/share/qutebrowser/** krw,
|
||||
|
||||
@@ -28,7 +28,7 @@ __copyright__ = "Copyright 2014-2015 Florian Bruhin (The Compiler)"
|
||||
__license__ = "GPL"
|
||||
__maintainer__ = __author__
|
||||
__email__ = "mail@qutebrowser.org"
|
||||
__version_info__ = (0, 4, 0)
|
||||
__version_info__ = (0, 4, 1)
|
||||
__version__ = '.'.join(map(str, __version_info__))
|
||||
__description__ = "A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit."
|
||||
|
||||
|
||||
@@ -424,19 +424,19 @@ def _init_modules(args, crash_handler):
|
||||
|
||||
def _init_late_modules(args):
|
||||
"""Initialize modules which can be inited after the window is shown."""
|
||||
try:
|
||||
log.init.debug("Reading web history...")
|
||||
reader = objreg.get('web-history').async_read()
|
||||
with debug.log_time(log.init, 'Reading history'):
|
||||
while True:
|
||||
QApplication.processEvents()
|
||||
log.init.debug("Reading web history...")
|
||||
reader = objreg.get('web-history').async_read()
|
||||
with debug.log_time(log.init, 'Reading history'):
|
||||
while True:
|
||||
QApplication.processEvents()
|
||||
try:
|
||||
next(reader)
|
||||
except StopIteration:
|
||||
pass
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
error.handle_fatal_exc(e, args, "Error while initializing!",
|
||||
pre_text="Error while initializing")
|
||||
sys.exit(usertypes.Exit.err_init)
|
||||
except StopIteration:
|
||||
break
|
||||
except (OSError, UnicodeDecodeError) as e:
|
||||
error.handle_fatal_exc(e, args, "Error while initializing!",
|
||||
pre_text="Error while initializing")
|
||||
sys.exit(usertypes.Exit.err_init)
|
||||
|
||||
|
||||
class Quitter:
|
||||
|
||||
@@ -1269,6 +1269,17 @@ class CommandDispatcher:
|
||||
except webelem.IsNullError:
|
||||
raise cmdexc.CommandError("Element vanished while editing!")
|
||||
|
||||
def _clear_search(self, view, text):
|
||||
"""Clear search string/highlights for the given view.
|
||||
|
||||
This does nothing if the view's search text is the same as the given
|
||||
text.
|
||||
"""
|
||||
if view.search_text is not None and view.search_text != text:
|
||||
# We first clear the marked text, then the highlights
|
||||
view.search('', 0)
|
||||
view.search('', QWebPage.HighlightAllOccurrences)
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', scope='window',
|
||||
maxsplit=0)
|
||||
def search(self, text="", reverse=False):
|
||||
@@ -1279,11 +1290,7 @@ class CommandDispatcher:
|
||||
reverse: Reverse search direction.
|
||||
"""
|
||||
view = self._current_widget()
|
||||
if view.search_text is not None and view.search_text != text:
|
||||
# We first clear the marked text, then the highlights
|
||||
view.search('', 0)
|
||||
view.search('', QWebPage.HighlightAllOccurrences)
|
||||
|
||||
self._clear_search(view, text)
|
||||
flags = 0
|
||||
ignore_case = config.get('general', 'ignore-case')
|
||||
if ignore_case == 'smart':
|
||||
@@ -1301,6 +1308,8 @@ class CommandDispatcher:
|
||||
view.search(text, flags | QWebPage.HighlightAllOccurrences)
|
||||
view.search_text = text
|
||||
view.search_flags = flags
|
||||
self._tabbed_browser.search_text = text
|
||||
self._tabbed_browser.search_flags = flags
|
||||
|
||||
@cmdutils.register(instance='command-dispatcher', hide=True,
|
||||
scope='window', count='count')
|
||||
@@ -1311,7 +1320,14 @@ class CommandDispatcher:
|
||||
count: How many elements to ignore.
|
||||
"""
|
||||
view = self._current_widget()
|
||||
if view.search_text is not None:
|
||||
|
||||
self._clear_search(view, self._tabbed_browser.search_text)
|
||||
|
||||
if self._tabbed_browser.search_text is not None:
|
||||
view.search_text = self._tabbed_browser.search_text
|
||||
view.search_flags = self._tabbed_browser.search_flags
|
||||
view.search(view.search_text,
|
||||
view.search_flags | QWebPage.HighlightAllOccurrences)
|
||||
for _ in range(count):
|
||||
view.search(view.search_text, view.search_flags)
|
||||
|
||||
@@ -1324,8 +1340,13 @@ class CommandDispatcher:
|
||||
count: How many elements to ignore.
|
||||
"""
|
||||
view = self._current_widget()
|
||||
if view.search_text is None:
|
||||
return
|
||||
self._clear_search(view, self._tabbed_browser.search_text)
|
||||
|
||||
if self._tabbed_browser.search_text is not None:
|
||||
view.search_text = self._tabbed_browser.search_text
|
||||
view.search_flags = self._tabbed_browser.search_flags
|
||||
view.search(view.search_text,
|
||||
view.search_flags | QWebPage.HighlightAllOccurrences)
|
||||
# The int() here serves as a QFlags constructor to create a copy of the
|
||||
# QFlags instance rather as a reference. I don't know why it works this
|
||||
# way, but it does.
|
||||
|
||||
@@ -127,7 +127,7 @@ class ErrorNetworkReply(QNetworkReply):
|
||||
"""We always have 0 bytes available."""
|
||||
return 0
|
||||
|
||||
def readData(self):
|
||||
def readData(self, _maxlen):
|
||||
"""No data available."""
|
||||
return bytes()
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ class WebView(QWebView):
|
||||
_check_insertmode: If True, in mouseReleaseEvent we should check if we
|
||||
need to enter/leave insert mode.
|
||||
_default_zoom_changed: Whether the zoom was changed from the default.
|
||||
_ignore_wheel_event: Ignore the next wheel event.
|
||||
See https://github.com/The-Compiler/qutebrowser/issues/395
|
||||
|
||||
Signals:
|
||||
scroll_pos_changed: Scroll percentage of current tab changed.
|
||||
@@ -103,6 +105,7 @@ class WebView(QWebView):
|
||||
self._old_scroll_pos = (-1, -1)
|
||||
self._zoom = None
|
||||
self._has_ssl_errors = False
|
||||
self._ignore_wheel_event = False
|
||||
self.keep_icon = False
|
||||
self.search_text = None
|
||||
self.search_flags = 0
|
||||
@@ -616,6 +619,7 @@ class WebView(QWebView):
|
||||
return
|
||||
self._mousepress_insertmode(e)
|
||||
self._mousepress_opentarget(e)
|
||||
self._ignore_wheel_event = True
|
||||
super().mousePressEvent(e)
|
||||
|
||||
def mouseReleaseEvent(self, e):
|
||||
@@ -638,6 +642,10 @@ class WebView(QWebView):
|
||||
Args:
|
||||
e: The QWheelEvent.
|
||||
"""
|
||||
if self._ignore_wheel_event:
|
||||
self._ignore_wheel_event = False
|
||||
# See https://github.com/The-Compiler/qutebrowser/issues/395
|
||||
return
|
||||
if e.modifiers() & Qt.ControlModifier:
|
||||
e.accept()
|
||||
divider = config.get('input', 'mouse-zoom-divider')
|
||||
|
||||
@@ -69,8 +69,8 @@ class UrlCompletionModel(base.BaseCompletionModel):
|
||||
bookmark_manager.removed.connect(self.on_bookmark_removed)
|
||||
|
||||
self._history = objreg.get('web-history')
|
||||
max_history = config.get('completion', 'web-history-max-items')
|
||||
history = utils.newest_slice(self._history, max_history)
|
||||
self._max_history = config.get('completion', 'web-history-max-items')
|
||||
history = utils.newest_slice(self._history, self._max_history)
|
||||
for entry in history:
|
||||
self._add_history_entry(entry)
|
||||
self._history.add_completion_item.connect(
|
||||
@@ -92,12 +92,19 @@ class UrlCompletionModel(base.BaseCompletionModel):
|
||||
else:
|
||||
return dt.strftime(fmt)
|
||||
|
||||
def _remove_oldest_history(self):
|
||||
"""Remove the oldest history entry."""
|
||||
self._history_cat.removeRow(0)
|
||||
|
||||
def _add_history_entry(self, entry):
|
||||
"""Add a new history entry to the completion."""
|
||||
self.new_item(self._history_cat, entry.url.toDisplayString(), "",
|
||||
self._fmt_atime(entry.atime), sort=int(entry.atime),
|
||||
userdata=entry.url)
|
||||
|
||||
if self._history_cat.rowCount() > self._max_history:
|
||||
self._remove_oldest_history()
|
||||
|
||||
@config.change_filter('completion', 'timestamp-format')
|
||||
def reformat_timestamps(self):
|
||||
"""Reformat the timestamps if the config option was changed."""
|
||||
|
||||
@@ -42,6 +42,9 @@ from qutebrowser.utils import (message, objreg, utils, standarddir, log,
|
||||
from qutebrowser.utils.usertypes import Completion
|
||||
|
||||
|
||||
UNSET = object()
|
||||
|
||||
|
||||
class change_filter: # pylint: disable=invalid-name
|
||||
|
||||
"""Decorator to filter calls based on a config section/option matching.
|
||||
@@ -619,9 +622,13 @@ class ConfigManager(QObject):
|
||||
return existed
|
||||
|
||||
@functools.lru_cache()
|
||||
def get(self, sectname, optname, raw=False, transformed=True):
|
||||
def get(self, sectname, optname, raw=False, transformed=True,
|
||||
fallback=UNSET):
|
||||
"""Get the value from a section/option.
|
||||
|
||||
We don't support the vars argument from configparser.get as it's not
|
||||
hashable.
|
||||
|
||||
Args:
|
||||
sectname: The section to get the option from.
|
||||
optname: The option name
|
||||
@@ -634,13 +641,18 @@ class ConfigManager(QObject):
|
||||
if not self._initialized:
|
||||
raise Exception("get got called before initialization was "
|
||||
"complete!")
|
||||
|
||||
try:
|
||||
sect = self.sections[sectname]
|
||||
except KeyError:
|
||||
if fallback is not UNSET:
|
||||
return fallback
|
||||
raise configexc.NoSectionError(sectname)
|
||||
try:
|
||||
val = sect[optname]
|
||||
except KeyError:
|
||||
if fallback is not UNSET:
|
||||
return fallback
|
||||
raise configexc.NoOptionError(optname, sectname)
|
||||
if raw:
|
||||
return val.value()
|
||||
|
||||
@@ -54,6 +54,8 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
emitted if the signal occurred in the current tab.
|
||||
|
||||
Attributes:
|
||||
search_text/search_flags: Search parameters which are shared between
|
||||
all tabs.
|
||||
_win_id: The window ID this tabbedbrowser is associated with.
|
||||
_filter: A SignalFilter instance.
|
||||
_now_focused: The tab which is focused now.
|
||||
@@ -108,6 +110,8 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
self._undo_stack = []
|
||||
self._filter = signalfilter.SignalFilter(win_id, self)
|
||||
self._now_focused = None
|
||||
self.search_text = None
|
||||
self.search_flags = 0
|
||||
objreg.get('config').changed.connect(self.update_favicons)
|
||||
objreg.get('config').changed.connect(self.update_window_title)
|
||||
objreg.get('config').changed.connect(self.update_tab_titles)
|
||||
|
||||
@@ -179,7 +179,7 @@ class IPCServer(QObject):
|
||||
self._atime_timer = None
|
||||
else:
|
||||
self._atime_timer = usertypes.Timer(self, 'ipc-atime')
|
||||
self._atime_timer.setInterval(READ_TIMEOUT)
|
||||
self._atime_timer.setInterval(ATIME_INTERVAL)
|
||||
self._atime_timer.timeout.connect(self.update_atime)
|
||||
self._atime_timer.setTimerType(Qt.VeryCoarseTimer)
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ def _os_info():
|
||||
lines = []
|
||||
releaseinfo = None
|
||||
if sys.platform == 'linux':
|
||||
osver = ', '.join([e for e in platform.dist() if e])
|
||||
osver = ''
|
||||
releaseinfo = _release_info()
|
||||
elif sys.platform == 'win32':
|
||||
osver = ', '.join(platform.win32_ver())
|
||||
|
||||
@@ -119,12 +119,7 @@ def check(fileobj, perfect_files):
|
||||
assert 0 <= branch_cov <= 100, branch_cov
|
||||
assert '\\' not in filename, filename
|
||||
|
||||
# Files without any branches have 0% coverage
|
||||
has_branches = klass.find('./lines/line[@branch="true"]') is not None
|
||||
if branch_cov < 100 and has_branches:
|
||||
is_bad = True
|
||||
else:
|
||||
is_bad = line_cov < 100
|
||||
is_bad = line_cov < 100 or branch_cov < 100
|
||||
|
||||
if filename in perfect_files and is_bad:
|
||||
messages.append(("{} has {}% line and {}% branch coverage!".format(
|
||||
|
||||
@@ -48,7 +48,7 @@ def brew(args, silent=False):
|
||||
with open(os.devnull, 'w') as f:
|
||||
subprocess.check_call(['brew'] + args, stdout=f)
|
||||
else:
|
||||
subprocess.check_call(['brew'] + args)
|
||||
subprocess.check_call(['brew'] + args + ['--verbose'])
|
||||
|
||||
|
||||
def check_setup(executable):
|
||||
@@ -97,7 +97,7 @@ elif os.environ.get('TRAVIS_OS_NAME', None) == 'osx':
|
||||
brew(['install', 'python3', 'pyqt5'])
|
||||
|
||||
print("Installing tox...")
|
||||
subprocess.check_call(['sudo', 'pip3.4', 'install', 'tox'])
|
||||
subprocess.check_call(['sudo', 'pip3', 'install', 'tox'])
|
||||
|
||||
check_setup('python3')
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ def pytest_collection_modifyitems(items):
|
||||
if 'qapp' in getattr(item, 'fixturenames', ()):
|
||||
item.add_marker('gui')
|
||||
if sys.platform == 'linux' and not os.environ.get('DISPLAY', ''):
|
||||
if 'CI' in os.environ:
|
||||
if ('CI' in os.environ and
|
||||
not os.environ.get('QUTE_NO_DISPLAY_OK', '')):
|
||||
raise Exception("No display available on CI!")
|
||||
skip_marker = pytest.mark.skipif(
|
||||
True, reason="No DISPLAY available")
|
||||
@@ -96,10 +97,11 @@ def pytest_runtest_setup(item):
|
||||
pytest.skip("Can only run when frozen!")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope='session')
|
||||
def change_qapp_name(qapp):
|
||||
@pytest.fixture(scope='session')
|
||||
def qapp(qapp):
|
||||
"""Change the name of the QApplication instance."""
|
||||
qapp.setApplicationName('qute_test')
|
||||
return qapp
|
||||
|
||||
|
||||
class WinRegistryHelper:
|
||||
|
||||
30
tests/test_conftest.py
Normal file
30
tests/test_conftest.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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/>.
|
||||
|
||||
"""Various meta-tests for conftest.py."""
|
||||
|
||||
|
||||
def test_qapp_name(qapp):
|
||||
"""Make sure the QApplication name is changed when we use qapp."""
|
||||
assert qapp.applicationName() == 'qute_test'
|
||||
|
||||
|
||||
def test_foo(request):
|
||||
"""Make sure a test without qapp doesn't use qapp (via autouse)."""
|
||||
assert 'qapp' not in request.fixturenames
|
||||
@@ -88,6 +88,6 @@ def test_error_network_reply(qtbot, req):
|
||||
assert reply.isFinished()
|
||||
assert not reply.isRunning()
|
||||
assert reply.bytesAvailable() == 0
|
||||
assert reply.readData() == b''
|
||||
assert reply.readData(1) == b''
|
||||
assert reply.error() == QNetworkReply.UnknownNetworkError
|
||||
assert reply.errorString() == "This is an error"
|
||||
|
||||
@@ -66,6 +66,9 @@ class TestConfigParser:
|
||||
|
||||
def test_transformed_option_old(self):
|
||||
"""Test a transformed option with the old name."""
|
||||
# WORKAROUND
|
||||
# Instance of 'object' has no 'name' member (no-member)
|
||||
# pylint: disable=no-member
|
||||
self.cp.read_dict({'colors': {'tab.fg.odd': 'pink'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
actual = self.cfg.get('colors', 'tabs.fg.odd').name()
|
||||
@@ -74,6 +77,9 @@ class TestConfigParser:
|
||||
|
||||
def test_transformed_option_new(self):
|
||||
"""Test a transformed section with the new name."""
|
||||
# WORKAROUND
|
||||
# Instance of 'object' has no 'name' member (no-member)
|
||||
# pylint: disable=no-member
|
||||
self.cp.read_dict({'colors': {'tabs.fg.odd': 'pink'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
actual = self.cfg.get('colors', 'tabs.fg.odd').name()
|
||||
@@ -154,6 +160,27 @@ class TestConfigParser:
|
||||
with pytest.raises(configexc.NoOptionError):
|
||||
self.cfg.get('general', 'bar') # pylint: disable=bad-config-call
|
||||
|
||||
def test_fallback(self):
|
||||
"""Test getting an option with fallback.
|
||||
|
||||
This is done during interpolation in later Python 3.4 versions.
|
||||
|
||||
See https://github.com/The-Compiler/qutebrowser/issues/968
|
||||
"""
|
||||
# pylint: disable=bad-config-call
|
||||
assert self.cfg.get('general', 'blabla', fallback='blub') == 'blub'
|
||||
|
||||
def test_sectionproxy(self):
|
||||
"""Test getting an option via the section proxy."""
|
||||
self.cp.read_dict({'general': {'ignore-case': 'false'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
assert not self.cfg['general'].get('ignore-case')
|
||||
|
||||
def test_sectionproxy_keyerror(self):
|
||||
"""Test getting an inexistent option via the section proxy."""
|
||||
with pytest.raises(configexc.NoOptionError):
|
||||
self.cfg['general'].get('blahblahblub')
|
||||
|
||||
|
||||
class TestKeyConfigParser:
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
"""Hypothesis tests for qutebrowser.config.configtypes."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import functools
|
||||
|
||||
@@ -44,6 +46,11 @@ def gen_classes():
|
||||
@hypothesis.given(strategies.text())
|
||||
@hypothesis.example('\x00')
|
||||
def test_configtypes_hypothesis(klass, s):
|
||||
if (klass in [configtypes.File, configtypes.UserStyleSheet] and
|
||||
sys.platform == 'linux' and
|
||||
not os.environ.get('DISPLAY', '')):
|
||||
pytest.skip("No DISPLAY available")
|
||||
|
||||
try:
|
||||
klass().validate(s)
|
||||
except configexc.ValidationError:
|
||||
|
||||
@@ -31,7 +31,7 @@ import subprocess
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
import py.path # pylint: disable=import-error
|
||||
import py.path # pylint: disable=no-name-in-module,import-error
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket, QAbstractSocket
|
||||
from PyQt5.QtTest import QSignalSpy
|
||||
@@ -45,10 +45,13 @@ from helpers import stubs # pylint: disable=import-error
|
||||
Args = collections.namedtuple('Args', 'basedir')
|
||||
|
||||
|
||||
pytestmark = pytest.mark.usefixtures('qapp')
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
def short_tmpdir():
|
||||
with tempfile.TemporaryDirectory() as tdir:
|
||||
yield py.path.local(tdir)
|
||||
yield py.path.local(tdir) # pylint: disable=no-member
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
@@ -676,6 +679,7 @@ class TestSendOrListen:
|
||||
assert "Connecting to {}".format(legacy_server._socketname) in msgs
|
||||
|
||||
@pytest.mark.posix # Unneeded on Windows
|
||||
@pytest.mark.not_frozen
|
||||
def test_stale_legacy_server(self, caplog, qtbot, args, legacy_server,
|
||||
ipc_server, py_proc):
|
||||
legacy_name = ipc._get_socketname(args.basedir, legacy=True)
|
||||
|
||||
@@ -126,7 +126,7 @@ def test_untested(covtest):
|
||||
pass
|
||||
""")
|
||||
covtest.run()
|
||||
expected = 'module.py has 75.0% line and 0.0% branch coverage!'
|
||||
expected = 'module.py has 75.0% line and 100.0% branch coverage!'
|
||||
assert covtest.check() == [expected]
|
||||
|
||||
|
||||
|
||||
@@ -451,25 +451,16 @@ class TestOsInfo:
|
||||
|
||||
"""Tests for _os_info."""
|
||||
|
||||
@pytest.mark.parametrize('dist, dist_str', [
|
||||
(('x', '', 'y'), 'x, y'),
|
||||
(('a', 'b', 'c'), 'a, b, c'),
|
||||
(('', '', ''), ''),
|
||||
])
|
||||
def test_linux_fake(self, monkeypatch, dist, dist_str):
|
||||
def test_linux_fake(self, monkeypatch):
|
||||
"""Test with a fake Linux.
|
||||
|
||||
Args:
|
||||
dist: The value to set platform.dist() to.
|
||||
dist_str: The expected distribution string in version._os_info().
|
||||
No args because osver is set to '' if the OS is linux.
|
||||
"""
|
||||
monkeypatch.setattr('qutebrowser.utils.version.sys.platform', 'linux')
|
||||
monkeypatch.setattr('qutebrowser.utils.version._release_info',
|
||||
lambda: [('releaseinfo', 'Hello World')])
|
||||
monkeypatch.setattr('qutebrowser.utils.version.platform.dist',
|
||||
lambda: dist)
|
||||
ret = version._os_info()
|
||||
expected = ['OS Version: {}'.format(dist_str), '',
|
||||
expected = ['OS Version: ', '',
|
||||
'--- releaseinfo ---', 'Hello World']
|
||||
assert ret == expected
|
||||
|
||||
|
||||
74
tox.ini
74
tox.ini
@@ -16,16 +16,16 @@ passenv = PYTHON DISPLAY XAUTHORITY HOME USERNAME USER CI
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
py==1.4.30
|
||||
pytest==2.7.2
|
||||
pytest==2.7.3 # rq.filter: <2.8.0
|
||||
pytest-capturelog==0.7
|
||||
pytest-qt==1.6.0
|
||||
pytest-mock==0.7.0
|
||||
pytest-qt==1.7.0
|
||||
pytest-mock==0.8.1
|
||||
pytest-html==1.6
|
||||
hypothesis==1.11.0
|
||||
hypothesis-pytest==0.18.1
|
||||
coverage==3.7.1
|
||||
hypothesis==1.11.4
|
||||
coverage==4.0.0
|
||||
pytest-cov==2.1.0
|
||||
beautifulsoup4==4.4.0
|
||||
beautifulsoup4==4.4.1
|
||||
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test --strict -rfEsw -m 'not integration' --cov qutebrowser --cov-report xml --cov-report=html --cov-report= {posargs:tests}
|
||||
@@ -35,7 +35,11 @@ commands =
|
||||
basepython = python3
|
||||
setenv = {[testenv]setenv}
|
||||
passenv = {[testenv]passenv}
|
||||
deps = {[testenv]deps}
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
httpbin==0.3.0
|
||||
itsdangerous==0.24
|
||||
Werkzeug==0.10.4
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test --strict -rfEsw -m 'integration' {posargs:tests}
|
||||
@@ -46,29 +50,29 @@ commands = {envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
envdir = {toxinidir}/.venv
|
||||
usedevelop = true
|
||||
|
||||
[testenv:unittests-watch]
|
||||
basepython = python3
|
||||
passenv = {[testenv]passenv}
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
pytest-testmon==0.6
|
||||
pytest-watch==3.2.0
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envdir}/bin/ptw -- --testmon --strict -rfEsw {posargs:tests}
|
||||
|
||||
[testenv:unittests-frozen]
|
||||
basepython = python3
|
||||
passenv = {[testenv]passenv}
|
||||
skip_install = true
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
{[testenv:py34-integration]deps}
|
||||
cx_Freeze==4.3.4
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} scripts/dev/freeze_tests.py build_exe -b {envdir}/build
|
||||
{envdir}/build/run-frozen-tests --strict -rfEsw {posargs}
|
||||
|
||||
[testenv:unittests-nodisp]
|
||||
basepython = python3
|
||||
passenv = {[testenv]passenv}
|
||||
deps = {[testenv]deps}
|
||||
setenv =
|
||||
DISPLAY=
|
||||
QUTE_NO_DISPLAY_OK=1
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test --strict -rfEw -m 'not integration' {posargs:tests}
|
||||
|
||||
[testenv:misc]
|
||||
basepython = python3
|
||||
# For global .gitignore files
|
||||
@@ -85,11 +89,9 @@ skip_install = true
|
||||
setenv = PYTHONPATH={toxinidir}/scripts/dev
|
||||
passenv =
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
{[testenv:py34-integration]deps}
|
||||
astroid==1.3.8
|
||||
beautifulsoup4==4.4.0
|
||||
pylint==1.4.4
|
||||
hypothesis==1.11.0
|
||||
logilab-common==1.0.2
|
||||
six==1.9.0
|
||||
commands =
|
||||
@@ -117,9 +119,9 @@ passenv =
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
py==1.4.30
|
||||
pytest==2.7.2
|
||||
pyflakes==0.9.2
|
||||
pytest-flakes==1.0.0
|
||||
pytest==2.7.3 # rq.filter: <2.8.0
|
||||
pyflakes==1.0.0
|
||||
pytest-flakes==1.0.1
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} -m py.test -q --flakes --ignore=tests
|
||||
@@ -130,7 +132,7 @@ passenv =
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
py==1.4.30
|
||||
pytest==2.7.2
|
||||
pytest==2.7.3 # rq.filter: <2.8.0
|
||||
pep8==1.6.2
|
||||
pytest-pep8==1.0.6
|
||||
commands =
|
||||
@@ -143,7 +145,7 @@ passenv =
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
py==1.4.30
|
||||
pytest==2.7.2
|
||||
pytest==2.7.3 # rq.filter: <2.8.0
|
||||
mccabe==0.3.1
|
||||
pytest-mccabe==0.1
|
||||
commands =
|
||||
@@ -184,24 +186,14 @@ commands =
|
||||
git --no-pager diff --exit-code --stat
|
||||
{envpython} scripts/asciidoc2html.py {posargs}
|
||||
|
||||
[testenv:smoke-frozen]
|
||||
basepython = python3
|
||||
passenv = {[testenv]passenv}
|
||||
skip_install = true
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
cx_Freeze==4.3.4
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} scripts/dev/freeze.py build_exe --qute-skip-html -b {envdir}/build
|
||||
{envdir}/build/qutebrowser --no-err-windows --nowindow --temp-basedir about:blank ":later 500 quit"
|
||||
|
||||
[testenv:cxfreeze-windows]
|
||||
# PYTHON is actually required when using this env, but the entire tox.ini would
|
||||
# fail if we didn't have a fallback defined.
|
||||
basepython = {env:PYTHON:}/python.exe
|
||||
skip_install = true
|
||||
deps = {[testenv:smoke-frozen]deps}
|
||||
deps =
|
||||
-r{toxinidir}/requirements.txt
|
||||
cx_Freeze==4.3.4
|
||||
commands =
|
||||
{envpython} scripts/link_pyqt.py --tox {envdir}
|
||||
{envpython} scripts/dev/freeze.py {posargs}
|
||||
|
||||
Reference in New Issue
Block a user