diff --git a/.pylintrc b/.pylintrc index d70a59273..4c64f485e 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,10 +3,10 @@ [MASTER] ignore=resources.py extension-pkg-whitelist=PyQt5,sip -load-plugins=pylint_checkers.config, - pylint_checkers.modeline, - pylint_checkers.openencoding, - pylint_checkers.settrace +load-plugins=qute_pylint.config, + qute_pylint.modeline, + qute_pylint.openencoding, + qute_pylint.settrace [MESSAGES CONTROL] enable=all diff --git a/.travis.yml b/.travis.yml index 658bee4c1..c72a05059 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ env: - TESTENV=unittests-nodisp - TESTENV=misc - TESTENV=vulture - - TESTENV=pydocstyle - TESTENV=flake8 - TESTENV=pyroma - TESTENV=check-manifest @@ -52,8 +51,6 @@ matrix: env: TESTENV=misc - os: osx env: TESTENV=vulture - - os: osx - env: TESTENV=pydocstyle - os: osx env: TESTENV=flake8 - os: osx diff --git a/README.asciidoc b/README.asciidoc index 3d7c4a276..8fdc2fb49 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -147,9 +147,9 @@ Contributors, sorted by the number of commits in descending order: * Bruno Oliveira * Alexander Cogneau * Martin Tournoij +* Felix Van der Jeugt * Raphael Pierzina * Joel Torstensson -* Felix Van der Jeugt * Claude * Patric Schmitz * meles5 @@ -184,6 +184,7 @@ Contributors, sorted by the number of commits in descending order: * Link * Larry Hynes * Johannes Altmanninger +* avk * Samir Benmendil * Regina Hug * Mathias Fussenegger diff --git a/pytest.ini b/pytest.ini index b754af883..e52ef27d8 100644 --- a/pytest.ini +++ b/pytest.ini @@ -9,13 +9,14 @@ markers = osx: Tests which only can run on OS X. not_osx: Tests which can not run on OS X. not_frozen: Tests which can't be run if sys.frozen is True. - not_xvfb: Tests which can't be run with Xvfb. + no_xvfb: Tests which can't be run with Xvfb. frozen: Tests which can only be run if sys.frozen is True. integration: Tests which test a bigger portion of code, run without coverage. skip: Always skipped test. pyqt531_or_newer: Needs PyQt 5.3.1 or newer. xfail_norun: xfail the test with out running it flaky: Tests which are flaky and should be rerun + ci: Tests which should only run on CI. qt_log_level_fail = WARNING qt_log_ignore = ^SpellCheck: .* diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 709914dde..b5695badc 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -714,6 +714,7 @@ class HintManager(QObject): if not elems: raise cmdexc.CommandError("No elements found.") hints = self._hint_strings(elems) + log.hints.debug("hints: {}".format(', '.join(hints))) for e, hint in zip(elems, hints): label = self._draw_label(e, hint) self._context.elems[hint] = ElemTuple(e, label) diff --git a/qutebrowser/misc/crashdialog.py b/qutebrowser/misc/crashdialog.py index 4a2244af4..213c38187 100644 --- a/qutebrowser/misc/crashdialog.py +++ b/qutebrowser/misc/crashdialog.py @@ -26,6 +26,7 @@ import html import getpass import fnmatch import traceback +import datetime import pkg_resources from PyQt5.QtCore import pyqtSlot, Qt, QSize, qVersion @@ -236,7 +237,9 @@ class _CrashDialog(QDialog): try: application = QApplication.instance() launch_time = application.launch_time.ctime() - self._crash_info.append(('Launch time', launch_time)) + crash_time = datetime.datetime.now().ctime() + text = 'Launch: {}\nCrash: {}'.format(launch_time, crash_time) + self._crash_info.append(('Timestamps', text)) except Exception: self._crash_info.append(("Launch time", traceback.format_exc())) try: diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 9023085cf..5047a2f61 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -51,10 +51,11 @@ else: colorama.deinit() # Log formats to use. -SIMPLE_FMT = '{levelname}: {message}' +SIMPLE_FMT = '{asctime:8} {levelname}: {message}' EXTENDED_FMT = ('{asctime:8} {levelname:8} {name:10} {module}:{funcName}:' '{lineno} {message}') -SIMPLE_FMT_COLORED = '%(log_color)s%(levelname)s%(reset)s: %(message)s' +SIMPLE_FMT_COLORED = ('%(green)s%(asctime)-8s%(reset)s ' + '%(log_color)s%(levelname)s%(reset)s: %(message)s') EXTENDED_FMT_COLORED = ( '%(green)s%(asctime)-8s%(reset)s ' '%(log_color)s%(levelname)-8s%(reset)s ' diff --git a/scripts/dev/freeze_tests.py b/scripts/dev/freeze_tests.py index 524dc1999..580033aae 100755 --- a/scripts/dev/freeze_tests.py +++ b/scripts/dev/freeze_tests.py @@ -55,8 +55,7 @@ def get_build_exe_options(): opts = freeze.get_build_exe_options(skip_html=True) opts['includes'] += pytest.freeze_includes() # pylint: disable=no-member opts['includes'] += ['unittest.mock', 'PyQt5.QtTest', 'hypothesis', 'bs4', - 'httpbin', 'jinja2.ext', 'xvfbwrapper', - 'cherrypy.wsgiserver', + 'httpbin', 'jinja2.ext', 'cherrypy.wsgiserver', 'cherrypy.wsgiserver.wsgiserver3', 'pstats'] httpbin_dir = os.path.dirname(httpbin.__file__) diff --git a/scripts/dev/pylint_checkers/__init__.py b/scripts/dev/pylint_checkers/qute_pylint/__init__.py similarity index 100% rename from scripts/dev/pylint_checkers/__init__.py rename to scripts/dev/pylint_checkers/qute_pylint/__init__.py diff --git a/scripts/dev/pylint_checkers/config.py b/scripts/dev/pylint_checkers/qute_pylint/config.py similarity index 100% rename from scripts/dev/pylint_checkers/config.py rename to scripts/dev/pylint_checkers/qute_pylint/config.py diff --git a/scripts/dev/pylint_checkers/modeline.py b/scripts/dev/pylint_checkers/qute_pylint/modeline.py similarity index 100% rename from scripts/dev/pylint_checkers/modeline.py rename to scripts/dev/pylint_checkers/qute_pylint/modeline.py diff --git a/scripts/dev/pylint_checkers/openencoding.py b/scripts/dev/pylint_checkers/qute_pylint/openencoding.py similarity index 100% rename from scripts/dev/pylint_checkers/openencoding.py rename to scripts/dev/pylint_checkers/qute_pylint/openencoding.py diff --git a/scripts/dev/pylint_checkers/settrace.py b/scripts/dev/pylint_checkers/qute_pylint/settrace.py similarity index 100% rename from scripts/dev/pylint_checkers/settrace.py rename to scripts/dev/pylint_checkers/qute_pylint/settrace.py diff --git a/scripts/dev/pylint_checkers/setup.py b/scripts/dev/pylint_checkers/setup.py new file mode 100644 index 000000000..eaecf406e --- /dev/null +++ b/scripts/dev/pylint_checkers/setup.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2016 Florian Bruhin (The Compiler) +# +# 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 . + +"""This is only here so we can install those plugins in tox.ini easily.""" + +from setuptools import setup +setup(name='qute_pylint', packages=['qute_pylint']) diff --git a/scripts/dev/run_frozen_tests.py b/scripts/dev/run_frozen_tests.py index 09782109b..ab933f595 100644 --- a/scripts/dev/run_frozen_tests.py +++ b/scripts/dev/run_frozen_tests.py @@ -28,7 +28,8 @@ import pytest_mock import pytest_catchlog import pytest_instafail import pytest_faulthandler +import pytest_xvfb sys.exit(pytest.main(plugins=[pytestqt.plugin, pytest_mock, pytest_catchlog, pytest_instafail, - pytest_faulthandler])) + pytest_faulthandler, pytest_xvfb])) diff --git a/scripts/dev/run_pylint_on_tests.py b/scripts/dev/run_pylint_on_tests.py index cb1e9e1db..01dd14ad7 100644 --- a/scripts/dev/run_pylint_on_tests.py +++ b/scripts/dev/run_pylint_on_tests.py @@ -60,7 +60,7 @@ def main(): ] toxinidir = sys.argv[1] - pythonpath = os.environ['PYTHONPATH'].split(os.pathsep) + [ + pythonpath = os.environ.get('PYTHONPATH', '').split(os.pathsep) + [ toxinidir, ] diff --git a/tests/conftest.py b/tests/conftest.py index 29e383996..bdfd96510 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,7 +34,6 @@ from helpers.messagemock import message_mock from helpers.fixtures import * # pylint: disable=wildcard-import from PyQt5.QtCore import PYQT_VERSION -import xvfbwrapper # Set hypothesis settings @@ -55,11 +54,10 @@ def _apply_platform_markers(item): "Can't be run when frozen"), ('frozen', not getattr(sys, 'frozen', False), "Can only run when frozen"), - ('not_xvfb', item.config.xvfb_display is not None, - "Can't be run with Xvfb."), ('skip', True, "Always skipped."), ('pyqt531_or_newer', PYQT_VERSION < 0x050301, "Needs PyQt 5.3.1 or newer"), + ('ci', 'CI' not in os.environ, "Only runs on CI."), ] for searched_marker, condition, default_reason in markers: @@ -147,41 +145,18 @@ def fail_tests_on_warnings(): def pytest_addoption(parser): - parser.addoption('--no-xvfb', action='store_true', default=False, - help='Disable xvfb in tests.') parser.addoption('--qute-delay', action='store', default=0, type=int, help="Delay between qutebrowser commands.") parser.addoption('--qute-profile-subprocs', action='store_true', default=False, help="Run cProfile for subprocesses.") -def pytest_configure(config): - """Start Xvfb if we're on Linux, not on a CI and Xvfb is available. - - This is a lot nicer than having windows popping up. - """ - config.xvfb_display = None - if os.environ.get('DISPLAY', None) == '': - # xvfbwrapper doesn't handle DISPLAY="" correctly - del os.environ['DISPLAY'] - - if (sys.platform.startswith('linux') and - not config.getoption('--no-xvfb') and - 'QUTE_NO_DISPLAY' not in os.environ): - assert 'QUTE_BUILDBOT' not in os.environ - try: - disp = xvfbwrapper.Xvfb(width=800, height=600, colordepth=16) - disp.start() - except FileNotFoundError: - # We run without Xvfb if it's unavailable. - pass - else: - config.xvfb_display = disp - - -def pytest_unconfigure(config): - if config.xvfb_display is not None: - config.xvfb_display.stop() +@pytest.fixture(scope='session', autouse=True) +def prevent_xvfb_on_buildbot(request): + if (not request.config.getoption('--no-xvfb') and + 'QUTE_BUILDBOT' in os.environ and + request.config.xvfb is not None): + raise Exception("Xvfb is running on buildbot!") @pytest.hookimpl(tryfirst=True, hookwrapper=True) diff --git a/tests/integration/data/hints/html/simple.html b/tests/integration/data/hints/html/simple.html new file mode 100644 index 000000000..40e908a13 --- /dev/null +++ b/tests/integration/data/hints/html/simple.html @@ -0,0 +1,13 @@ + + + + + + + + Simple link + + + Follow me! + + diff --git a/tests/integration/features/conftest.py b/tests/integration/features/conftest.py index 501e1940d..03559ede7 100644 --- a/tests/integration/features/conftest.py +++ b/tests/integration/features/conftest.py @@ -212,12 +212,7 @@ def path_should_be_loaded(quteproc, path): This is usally the better check compared to "should be requested" as the page could be loaded from local cache. """ - url = quteproc.path_to_url(path) - pattern = re.compile( - r"load status for : LoadStatus\.success".format( - url=re.escape(url))) - quteproc.wait_for(message=pattern) + quteproc.wait_for_load_finished(path) @bdd.then(bdd.parsers.parse("{path} should be requested")) diff --git a/tests/integration/features/keyinput.feature b/tests/integration/features/keyinput.feature index eae967874..1d930da24 100644 --- a/tests/integration/features/keyinput.feature +++ b/tests/integration/features/keyinput.feature @@ -113,7 +113,7 @@ Feature: Keyboard input Then the javascript message "key press: 88" should be logged And the javascript message "key release: 88" should be logged - @not_xvfb @posix + @no_xvfb @posix Scenario: :fake-key sending key to the website with other window focused When I open data/keyinput/log.html And I set general -> developer-extras to true diff --git a/tests/integration/features/misc.feature b/tests/integration/features/misc.feature index 38a77d6e6..7a0f9ae2f 100644 --- a/tests/integration/features/misc.feature +++ b/tests/integration/features/misc.feature @@ -108,7 +108,7 @@ Feature: Various utility commands. And I run :inspector Then the error "Please enable developer-extras before using the webinspector!" should be shown - @not_xvfb @posix + @no_xvfb @posix Scenario: Inspector smoke test When I set general -> developer-extras to true And I run :inspector @@ -124,7 +124,7 @@ Feature: Various utility commands. Then the error "Please enable developer-extras before using the webinspector!" should be shown # Different code path as an inspector got created now - @not_xvfb @posix + @no_xvfb @posix Scenario: Inspector smoke test 2 When I set general -> developer-extras to true And I run :inspector @@ -202,7 +202,7 @@ Feature: Various utility commands. # :debug-console - @not_xvfb + @no_xvfb Scenario: :debug-console smoke test When I run :debug-console And I wait for "Focus object changed: " in the log diff --git a/tests/integration/features/prompts.feature b/tests/integration/features/prompts.feature index 94059f399..b4a5091ac 100644 --- a/tests/integration/features/prompts.feature +++ b/tests/integration/features/prompts.feature @@ -122,12 +122,14 @@ Feature: Prompts And I click the button Then the javascript message "geolocation permission denied" should be logged + @ci Scenario: Always accepting geolocation When I set content -> geolocation to true And I open data/prompt/geolocation.html in a new tab And I click the button Then the javascript message "geolocation permission denied" should not be logged + @ci Scenario: geolocation with ask -> true When I set content -> geolocation to ask And I open data/prompt/geolocation.html in a new tab diff --git a/tests/integration/quteprocess.py b/tests/integration/quteprocess.py index 21f811193..5b9fb3281 100644 --- a/tests/integration/quteprocess.py +++ b/tests/integration/quteprocess.py @@ -380,7 +380,7 @@ class QuteProc(testprocess.Process): url = utils.elide(QUrl(url).toDisplayString(QUrl.EncodeUnicode), 100) pattern = re.compile( r"(load status for : LoadStatus\.{load_status}|fetch: " + r"tab_id=\d+ url='{url}/?'>: LoadStatus\.{load_status}|fetch: " r"PyQt5\.QtCore\.QUrl\('{url}'\) -> .*)".format( load_status=re.escape(load_status), url=re.escape(url))) self.wait_for(message=pattern, timeout=timeout) diff --git a/tests/integration/test_hints_html.py b/tests/integration/test_hints_html.py new file mode 100644 index 000000000..cc668193d --- /dev/null +++ b/tests/integration/test_hints_html.py @@ -0,0 +1,56 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2016 Florian Bruhin (The Compiler) +# +# 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 . + +"""Test hints based on html files with special comments.""" + +import os +import os.path + +import yaml +import pytest +import bs4 + + +def collect_tests(): + basedir = os.path.dirname(__file__) + datadir = os.path.join(basedir, 'data', 'hints', 'html') + files = os.listdir(datadir) + return files + + +@pytest.mark.parametrize('test_name', collect_tests()) +def test_hints(test_name, quteproc): + file_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), + 'data', 'hints', 'html', test_name) + url_path = 'data/hints/html/{}'.format(test_name) + quteproc.open_path(url_path) + quteproc.wait_for_load_finished(url_path) + + with open(file_path, 'r', encoding='utf-8') as html: + soup = bs4.BeautifulSoup(html, 'html.parser') + + comment = soup.find(text=lambda text: isinstance(text, bs4.Comment)) + parsed = yaml.load(comment) + + assert set(parsed.keys()) == {'target'} + + quteproc.send_cmd(':hint links normal') + quteproc.wait_for(message='hints: a', category='hints') + quteproc.send_cmd(':follow-hint a') + quteproc.wait_for_load_finished('data/' + parsed['target']) diff --git a/tests/unit/mainwindow/statusbar/test_textbase.py b/tests/unit/mainwindow/statusbar/test_textbase.py index c33b11b0b..2b9bd4cc1 100644 --- a/tests/unit/mainwindow/statusbar/test_textbase.py +++ b/tests/unit/mainwindow/statusbar/test_textbase.py @@ -46,7 +46,7 @@ def test_elided_text(qtbot, elidemode, check): """ label = TextBase(elidemode=elidemode) qtbot.add_widget(label) - long_string = 'Hello world! ' * 20 + long_string = 'Hello world! ' * 100 label.setText(long_string) label.resize(100, 50) label.show() diff --git a/tox.ini b/tox.ini index b64bc9815..9166a4bc1 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py34,py35-cov,misc,vulture,pydocstyle,flake8,pylint,pyroma,check-manifest +envlist = py34,py35-cov,misc,vulture,flake8,pylint,pyroma,check-manifest [testenv] # https://bitbucket.org/hpk42/tox/issue/246/ - only needed for Windows though @@ -20,7 +20,7 @@ deps = Flask==0.10.1 glob2==0.4.1 httpbin==0.4.1 - hypothesis==2.0.0 + hypothesis==3.0.2 itsdangerous==0.24 Mako==1.0.3 parse==1.6.6 @@ -38,12 +38,12 @@ deps = pytest-travis-fold==1.2.0 pytest-repeat==0.2 pytest-rerunfailures==1.0.1 + pytest-xvfb==0.1.0 six==1.10.0 termcolor==1.1.0 vulture==0.8.1 Werkzeug==0.11.4 wheel==0.29.0 - xvfbwrapper==0.2.8 cherrypy==5.0.1 commands = {envpython} scripts/link_pyqt.py --tox {envdir} @@ -122,8 +122,6 @@ commands = [testenv:pylint] basepython = python3 ignore_errors = true -skip_install = true -setenv = PYTHONPATH={toxinidir}/scripts/dev passenv = deps = {[testenv]deps} @@ -131,6 +129,7 @@ deps = astroid==1.4.4 pylint==1.5.4 requests==2.9.1 + ./scripts/dev/pylint_checkers commands = {envpython} scripts/link_pyqt.py --tox {envdir} {envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no @@ -138,26 +137,18 @@ commands = [testenv:pylint-tip] basepython = python3 -skip_install = true -setenv = {[testenv:pylint]setenv} passenv = {[testenv:pylint]passenv} deps = {[testenv]deps} {[testenv:misc]deps} hg+https://bitbucket.org/logilab/astroid hg+https://bitbucket.org/logilab/pylint + ./scripts/dev/pylint_checkers commands = {envpython} scripts/link_pyqt.py --tox {envdir} {envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {envpython} scripts/dev/run_pylint_on_tests.py --output-format=colorized --reports=no -[testenv:pydocstyle] -basepython = python3 -skip_install = true -passenv = PYTHON LANG -deps = pydocstyle==1.0.0 -commands = {envpython} -m pydocstyle scripts tests qutebrowser - [testenv:flake8] basepython = python3 passenv = @@ -176,8 +167,9 @@ deps = flake8-deprecated==0.2 flake8-mock==0.2 flake8-pep3101==0.2 - flake8-pep257==1.0.5 - pep257==0.7.0 + flake8-docstrings==0.2.5 + pep257==0.7.0 # still needed by flake8-docstrings but ignored + pydocstyle==1.0.0 commands = {envpython} -m flake8