From 9a02dc174d5283fee9aefb9a6ffdabf605cfb014 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Feb 2016 07:34:35 +0100 Subject: [PATCH 1/9] bdd: use quteproc.wait_for_load_finished. Why duplicate that logic? --- tests/integration/features/conftest.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/integration/features/conftest.py b/tests/integration/features/conftest.py index 501e1940d..9c47d1337 100644 --- a/tests/integration/features/conftest.py +++ b/tests/integration/features/conftest.py @@ -213,11 +213,7 @@ def path_should_be_loaded(quteproc, path): 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")) From 9b1db7ec0bfe37e63d54848ac93fa230d73e111b Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Feb 2016 07:34:51 +0100 Subject: [PATCH 2/9] hints: Log the used hint chars Useful for debugging and for end2end tests. --- qutebrowser/browser/hints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index c9a722dc6..26fd02fbc 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -677,6 +677,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) From 36b0e304fc46cd6821be1804bc8f9fae280b9cef Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Feb 2016 07:35:14 +0100 Subject: [PATCH 3/9] tests: Add first end-to-end test for hints. This is based on HTML files with a global YAML comment, currently with "target" as the only allowed key. The tests then do this: - Open a HTML file in data/hints/html - Start hinting - Make sure only one hint is visible - Follow it, and make sure the page mentioned in "target:" is reached Some ideas for the future: - A "scroll" key, to scroll before hinting - A "zoom" key, to zoom - Multiple hints via a list - Checking position of hints? - A mode to manually check the pages (to check hint positions) --- tests/integration/data/hints/html/simple.html | 13 +++++ tests/integration/test_hints_html.py | 56 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/integration/data/hints/html/simple.html create mode 100644 tests/integration/test_hints_html.py 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/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']) From 0c4a961505b6ef9906c78ced8ee49984053344a3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Feb 2016 20:33:14 +0100 Subject: [PATCH 4/9] tox: Upgrade hypothesis to 3.0.2. (3.0.2: performance fix) ------------------ 3.0.1 - 2016-02-18 ------------------ * Fix a case where it was possible to trigger an "Unreachable" assertion when running certain flaky stateful tests. * Improve shrinking of large stateful tests by eliminating a case where it was hard to delete early steps. * Improve efficiency of drawing binary(min_size=n, max_size=n) significantly by provide a custom implementation for fixed size blocks that can bypass a lot of machinery. * Set default home directory based on the current working directory at the point Hypothesis is imported, not whenever the function first happens to be called. ------------------ 3.0.0 - 2016-02-17 ------------------ Codename: This really should have been 2.1. Externally this looks like a very small release. It has one small breaking change that probably doesn't affect anyone at all (some behaviour that never really worked correctly is now outright forbidden) but necessitated a major version bump and one visible new feature. Internally this is a complete rewrite. Almost nothing other than the public API is the same. New features: * Addition of data() strategy which allows you to draw arbitrary data interactively within the test. * New "exploded" database format which allows you to more easily check the example database into a source repository while supporting merging. * Better management of how examples are saved in the database. * Health checks will now raise as errors when they fail. It was too easy to have the warnings be swallowed entirely. New limitations: * choices and streaming strategies may no longer be used with find(). Neither may data() (this is the change that necessitated a major version bump). Feature removal: * The ForkingTestCase executor has gone away. It may return in some more working form at a later date. Performance improvements: * A new model which allows flatmap, composite strategies and stateful testing to perform *much* better. They should also be more reliable. * Filtering may in some circumstances have improved significantly. This will help especially in cases where you have lots of values with individual filters on them, such as lists(x.filter(...)). * Modest performance improvements to the general test runner by avoiding expensive operations In general your tests should have got faster. If they've instead got significantly slower, I'm interested in hearing about it. Data distribution: The data distribution should have changed significantly. This may uncover bugs the previous version missed. It may also miss bugs the previous version could have uncovered. Hypothesis is now producing less strongly correlated data than it used to, but the correlations are extended over more of the structure. Shrinking: Shrinking quality should have improved. In particular Hypothesis can now perform simultaneous shrinking of separate examples within a single test (previously it was only able to do this for elements of a single collection). In some cases performance will have improved, in some cases it will have got worse but generally shouldn't have by much. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 465c393fd..166e877b1 100644 --- a/tox.ini +++ b/tox.ini @@ -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 From 6a077f5d5a07c56190b63f9cdae5d76a816a7261 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Feb 2016 21:38:23 +0100 Subject: [PATCH 5/9] Fix lint. --- tests/integration/features/conftest.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/features/conftest.py b/tests/integration/features/conftest.py index 9c47d1337..03559ede7 100644 --- a/tests/integration/features/conftest.py +++ b/tests/integration/features/conftest.py @@ -212,7 +212,6 @@ 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) quteproc.wait_for_load_finished(path) From b201b65669fe3d69d4a933ec1e22aae625644f74 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 19 Feb 2016 06:42:23 +0100 Subject: [PATCH 6/9] tests: Handle trailing / in wait_for_load_finished. We actually already added that in 16ec0354188abee95fb55504d83815b916e61d52, but in 9a02dc174d5283fee9aefb9a6ffdabf605cfb014 we accidentally dropped it again. --- tests/integration/quteprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 67b99047726668cb3479914d9a8fb9ce68cc35f8 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 19 Feb 2016 06:52:19 +0100 Subject: [PATCH 7/9] Include pytest-xvfb properly in frozen tests --- scripts/dev/run_frozen_tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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])) From 0b362e76eac75f9e35f6501d3fbaa13cfedd4b78 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 19 Feb 2016 07:09:13 +0100 Subject: [PATCH 8/9] Move pylint plugins to an installed package. This means we can now run things like running pylint --version without having to set PYTHONPATH correctly now. When using skip_install=true, the plugins wouldn't work as they need to import qutebrowser. We have to keep setting PYTHONPATH in run_pylint_on_tests.py, otherwise we get this error I don't quite understand: F: 1, 0: error while code parsing: Unable to load file '/home/florian/proj/qutebrowser/git/__init__.py' ([Errno 2] No such file or directory: '...') (parse-error) --- .pylintrc | 8 ++++---- scripts/dev/pylint_checkers/{ => qute_pylint}/__init__.py | 0 scripts/dev/pylint_checkers/{ => qute_pylint}/config.py | 0 scripts/dev/pylint_checkers/{ => qute_pylint}/modeline.py | 0 .../dev/pylint_checkers/{ => qute_pylint}/openencoding.py | 0 scripts/dev/pylint_checkers/{ => qute_pylint}/settrace.py | 0 scripts/dev/pylint_checkers/setup.py | 4 ++++ scripts/dev/run_pylint_on_tests.py | 2 +- tox.ini | 6 ++---- 9 files changed, 11 insertions(+), 9 deletions(-) rename scripts/dev/pylint_checkers/{ => qute_pylint}/__init__.py (100%) rename scripts/dev/pylint_checkers/{ => qute_pylint}/config.py (100%) rename scripts/dev/pylint_checkers/{ => qute_pylint}/modeline.py (100%) rename scripts/dev/pylint_checkers/{ => qute_pylint}/openencoding.py (100%) rename scripts/dev/pylint_checkers/{ => qute_pylint}/settrace.py (100%) create mode 100644 scripts/dev/pylint_checkers/setup.py 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/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..b1a4ede88 --- /dev/null +++ b/scripts/dev/pylint_checkers/setup.py @@ -0,0 +1,4 @@ +# 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_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/tox.ini b/tox.ini index 166e877b1..40da3f154 100644 --- a/tox.ini +++ b/tox.ini @@ -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,14 +137,13 @@ 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 From d0e79b2af760475b989e96603acb00e65f9d54a2 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 19 Feb 2016 07:39:17 +0100 Subject: [PATCH 9/9] Fix lint --- scripts/dev/pylint_checkers/setup.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/dev/pylint_checkers/setup.py b/scripts/dev/pylint_checkers/setup.py index b1a4ede88..eaecf406e 100644 --- a/scripts/dev/pylint_checkers/setup.py +++ b/scripts/dev/pylint_checkers/setup.py @@ -1,4 +1,25 @@ -# This is only here so we can install those plugins in tox.ini easily. +#!/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'])