diff --git a/.pylintrc b/.pylintrc index 58a3b9ec9..d0d2918cc 100644 --- a/.pylintrc +++ b/.pylintrc @@ -21,7 +21,8 @@ disable=no-self-use, bad-option-value, bad-continuation, too-many-instance-attributes, - unnecessary-lambda + unnecessary-lambda, + blacklisted-name [BASIC] module-rgx=(__)?[a-z][a-z0-9_]*(__)?$ @@ -33,7 +34,6 @@ argument-rgx=[a-z_][a-z0-9_]{0,30}$ variable-rgx=[a-z_][a-z0-9_]{0,30}$ class-attribute-rgx=[A-Za-z_][A-Za-z0-9_]{1,30}$ inlinevar-rgx=[a-z_][a-z0-9_]*$ -bad-names=foo,tmp [FORMAT] max-line-length=79 diff --git a/qutebrowser/test/keyinput/test_basekeyparser.py b/qutebrowser/test/keyinput/test_basekeyparser.py index f01e2555b..2500c447b 100644 --- a/qutebrowser/test/keyinput/test_basekeyparser.py +++ b/qutebrowser/test/keyinput/test_basekeyparser.py @@ -17,19 +17,25 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring - """Tests for BaseKeyParser.""" import unittest import logging -from unittest import TestCase from unittest.mock import Mock import qutebrowser.keyinput.basekeyparser as basekeyparser +from qutebrowser.test.stubs import ConfigStub, FakeKeyEvent from PyQt5.QtCore import Qt +CONFIG = {'test': {'': 'ctrla', + 'a': 'a', + 'ba': 'ba', + 'ax': 'ax', + 'ccc': 'ccc'}, + 'input': {'timeout': 100}, + 'test2': {'foo': 'bar', '': 'ctrlx'}} + def setUpModule(): """Mock out some imports in basekeyparser.""" @@ -37,54 +43,7 @@ def setUpModule(): logging.disable(logging.ERROR) -class ConfigStub: - - """Stub for basekeyparser.config. - - Class attributes: - DATA: The config data to return. - """ - - DATA = {'test': {'': 'ctrla', - 'a': 'a', - 'ba': 'ba', - 'ax': 'ax', - 'ccc': 'ccc'}, - 'input': {'timeout': 100}, - 'test2': {'foo': 'bar', '': 'ctrlx'}} - - def section(self, name): - """Get a section from the config. - - Args: - name: The section name to get. - - Raise: - ValueError if section isn't test1/test2. - - Return: - The section as dict. - """ - if name not in ('test', 'test2'): - raise ValueError("section called with section '{}'!".format(name)) - return self.DATA[name] - - def get(self, sect, opt): - """Get a value from the config.""" - return self.DATA[sect][opt] - - -class FakeKeyEvent: - - """Fake QKeyPressEvent stub.""" - - def __init__(self, key, modifiers=0, text=''): - self.key = Mock(return_value=key) - self.text = Mock(return_value=text) - self.modifiers = Mock(return_value=modifiers) - - -class NormalizeTests(TestCase): +class NormalizeTests(unittest.TestCase): """Test _normalize_keystr method.""" @@ -105,7 +64,7 @@ class NormalizeTests(TestCase): self.assertEqual(self.kp._normalize_keystr(orig), repl, orig) -class SplitCountTests(TestCase): +class SplitCountTests(unittest.TestCase): """Test the _split_count method. @@ -148,12 +107,12 @@ class SplitCountTests(TestCase): self.assertEqual(self.kp._split_count(), (None, '10foo')) -class ReadConfigTests(TestCase): +class ReadConfigTests(unittest.TestCase): """Test reading the config.""" def setUp(self): - basekeyparser.config = ConfigStub() + basekeyparser.config = ConfigStub(CONFIG) basekeyparser.QTimer = Mock() def test_read_config_invalid(self): @@ -176,7 +135,7 @@ class ReadConfigTests(TestCase): self.assertIn('Ctrl+X', kp.special_bindings) -class SpecialKeysTests(TestCase): +class SpecialKeysTests(unittest.TestCase): """Check execute() with special keys. @@ -185,7 +144,7 @@ class SpecialKeysTests(TestCase): """ def setUp(self): - basekeyparser.config = ConfigStub() + basekeyparser.config = ConfigStub(CONFIG) basekeyparser.QTimer = Mock() self.kp = basekeyparser.BaseKeyParser() self.kp.execute = Mock() @@ -210,7 +169,7 @@ class SpecialKeysTests(TestCase): self.assertFalse(self.kp.execute.called) -class KeyChainTests(TestCase): +class KeyChainTests(unittest.TestCase): """Test execute() with keychain support. @@ -221,7 +180,7 @@ class KeyChainTests(TestCase): def setUp(self): """Set up mocks and read the test config.""" - basekeyparser.config = ConfigStub() + basekeyparser.config = ConfigStub(CONFIG) self.timermock = Mock() basekeyparser.QTimer = Mock(return_value=self.timermock) self.kp = basekeyparser.BaseKeyParser(supports_chains=True, @@ -279,12 +238,12 @@ class KeyChainTests(TestCase): self.assertEqual(self.kp._keystring, '') -class CountTests(TestCase): +class CountTests(unittest.TestCase): """Test execute() with counts.""" def setUp(self): - basekeyparser.config = ConfigStub() + basekeyparser.config = ConfigStub(CONFIG) basekeyparser.QTimer = Mock() self.kp = basekeyparser.BaseKeyParser(supports_chains=True, supports_count=True) diff --git a/qutebrowser/test/stubs.py b/qutebrowser/test/stubs.py new file mode 100644 index 000000000..e5055e587 --- /dev/null +++ b/qutebrowser/test/stubs.py @@ -0,0 +1,258 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014 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 . + +# pylint: disable=invalid-name + +"""Fake objects/stubs.""" + +from unittest.mock import Mock + +from PyQt5.QtCore import QPoint, QProcess +from PyQt5.QtWebKit import QWebElement + + +class ConfigStub: + + """Stub for basekeyparser.config. + + Attributes: + data: The config data to return. + """ + + class NoOptionError(Exception): + + """NoOptionError exception.""" + + pass + + def __init__(self, data): + self.data = data + + def section(self, name): + """Get a section from the config. + + Args: + name: The section name to get. + + Raise: + ValueError if section isn't test1/test2. + + Return: + The section as dict. + """ + return self.data[name] + + def get(self, sect, opt): + """Get a value from the config.""" + sect = self.data[sect] + try: + return sect[opt] + except KeyError: + raise self.NoOptionError + + +class FakeKeyEvent: + + """Fake QKeyPressEvent stub.""" + + def __init__(self, key, modifiers=0, text=''): + self.key = Mock(return_value=key) + self.text = Mock(return_value=text) + self.modifiers = Mock(return_value=modifiers) + + +class FakeWebElement: + + """A stub for QWebElement.""" + + def __init__(self, geometry=None, frame=None, null=False, visibility='', + display='', attributes=None): + """Constructor. + + Args: + geometry: The geometry of the QWebElement as QRect. + frame: The QWebFrame the element is in. + null: Whether the element is null or not. + visibility: The CSS visibility style property calue. + display: The CSS display style property calue. + attributes: Boolean HTML attributes to be added. + + Raise: + ValueError if element is not null and geometry/frame are not given. + """ + self.geometry = Mock(return_value=geometry) + self.webFrame = Mock(return_value=frame) + self.isNull = Mock(return_value=null) + self._visibility = visibility + self._display = display + self._attributes = attributes + + def styleProperty(self, name, strategy): + """Return the CSS style property named name. + + Only display/visibility and ComputedStyle are simulated. + + Raise: + ValueError if strategy is not ComputedStyle or name is not + visibility/display. + """ + if strategy != QWebElement.ComputedStyle: + raise ValueError("styleProperty called with strategy != " + "ComputedStyle ({})!".format(strategy)) + if name == 'visibility': + return self._visibility + elif name == 'display': + return self._display + else: + raise ValueError("styleProperty called with unknown name " + "'{}'".format(name)) + + def hasAttribute(self, name): + """Check if the element has an attribute named name.""" + if self._attributes is None: + return False + else: + return name in self._attributes + + +class FakeWebFrame: + + """A stub for QWebFrame.""" + + def __init__(self, geometry, scroll=None, parent=None): + """Constructor. + + Args: + geometry: The geometry of the frame as QRect. + scroll: The scroll position as QPoint. + parent: The parent frame. + """ + if scroll is None: + scroll = QPoint(0, 0) + self.geometry = Mock(return_value=geometry) + self.scrollPosition = Mock(return_value=scroll) + self.parentFrame = Mock(return_value=parent) + + +class FakeChildrenFrame: + + """A stub for QWebFrame to test get_child_frames.""" + + def __init__(self, children=None): + if children is None: + children = [] + self.childFrames = Mock(return_value=children) + + +class FakeQApplication: + + """Stub to insert as QApplication module.""" + + def __init__(self, focus): + # pylint: disable=invalid-name + self.focusWidget = Mock(return_value=focus) + self.instance = Mock(return_value=self) + + +class FakeUrl: + + """QUrl stub which provides .path().""" + + def __init__(self, path=None): + self.path = Mock(return_value=path) + + +class FakeNetworkReply: + + """QNetworkReply stub which provides a Content-Disposition header.""" + + def __init__(self, content_disposition=None, url=None): + if url is None: + url = FakeUrl() + self._content_disposition = content_disposition + self.url = Mock(return_value=url) + + def hasRawHeader(self, name): + """Check if the reply has a certain header. + + Args: + name: The name of the header. + + Return: + True if the header is present, False if not. + + Raise: + ValueError: If a header other than Content-Disposition is + requested. + """ + if name == 'Content-Disposition': + return self._content_disposition is not None + else: + raise ValueError("Invalid header {}".format(name)) + + def rawHeader(self, name): + """Get the raw header data of a header. + + Args: + name: The name of the header. + + Return: + The header data, as ISO-8859-1 encoded bytes() object. + + Raise: + ValueError: If a header other than Content-Disposition is + requested. + """ + if name != 'Content-Disposition': + raise ValueError("Invalid header {}".format(name)) + cd = self._content_disposition + if cd is None: + raise ValueError("Content-Disposition is None!") + return cd.encode('iso-8859-1') + + +class FakeQProcess: + + """QProcess stub. + + Gets some enum values from the real QProcess and uses mocks for signals. + """ + + NormalExit = QProcess.NormalExit + CrashExit = QProcess.CrashExit + + FailedToStart = QProcess.FailedToStart + Crashed = QProcess.Crashed + Timedout = QProcess.Timedout + WriteError = QProcess.WriteError + ReadError = QProcess.ReadError + UnknownError = QProcess.UnknownError + + def __init__(self, parent=None): # pylint: disable=unused-argument + self.finished = Mock() + self.error = Mock() + self.start = Mock() + + +class FakeSignal: + + """Fake pyqtSignal stub which uses a mock to see if it was called.""" + + def __init__(self, name='fake'): + self.signal = '2{}(int, int)'.format(name) diff --git a/qutebrowser/test/test_helpers.py b/qutebrowser/test/test_helpers.py index d764d0481..250c99fde 100644 --- a/qutebrowser/test/test_helpers.py +++ b/qutebrowser/test/test_helpers.py @@ -22,12 +22,12 @@ """Test test helpers.""" import os -from unittest import TestCase +import unittest from qutebrowser.test.helpers import environ_set_temp -class TestEnvironSetTemp(TestCase): +class TestEnvironSetTemp(unittest.TestCase): """Test the environ_set_temp helper.""" @@ -48,3 +48,6 @@ class TestEnvironSetTemp(TestCase): if 'QUTEBROWSER_ENVIRON_TEST' in os.environ: # if some test failed del os.environ['QUTEBROWSER_ENVIRON_TEST'] + +if __name__ == '__main__': + unittest.main() diff --git a/qutebrowser/test/utils/test_debug.py b/qutebrowser/test/utils/test_debug.py index 57115f2fb..c4fb64c9c 100644 --- a/qutebrowser/test/utils/test_debug.py +++ b/qutebrowser/test/utils/test_debug.py @@ -15,45 +15,37 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=pointless-statement,no-member - """Tests for qutebrowser.utils.debug.""" import unittest -from unittest import TestCase from PyQt5.QtWidgets import QStyle, QFrame import qutebrowser.utils.debug as debug +from qutebrowser.test.stubs import FakeSignal -class FakeSignal: - - """Fake pyqtSignal stub which uses a mock to see if it was called.""" - - def __init__(self, name='fake'): - self.signal = '2{}(int, int)'.format(name) - - -class QEnumKeyTests(TestCase): +class QEnumKeyTests(unittest.TestCase): """Tests for qenum_key.""" def test_no_metaobj(self): """Test with an enum with no metaobject.""" with self.assertRaises(AttributeError): + # pylint: disable=pointless-statement,no-member QStyle.PrimitiveElement.staticMetaObject key = debug.qenum_key(QStyle, QStyle.PE_PanelButtonCommand) self.assertEqual(key, 'PE_PanelButtonCommand') def test_metaobj(self): """Test with an enum with metaobject.""" + # pylint: disable=pointless-statement QFrame.staticMetaObject key = debug.qenum_key(QFrame, QFrame.Sunken) self.assertEqual(key, 'Sunken') -class TestDebug(TestCase): +class TestDebug(unittest.TestCase): """Test signal debug output functions.""" diff --git a/qutebrowser/test/utils/test_editor.py b/qutebrowser/test/utils/test_editor.py index 70ec02d85..48bb7f970 100644 --- a/qutebrowser/test/utils/test_editor.py +++ b/qutebrowser/test/utils/test_editor.py @@ -17,61 +17,17 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=maybe-no-member - """Tests for qutebrowser.utils.editor.""" import os import os.path import unittest -from unittest import TestCase from unittest.mock import Mock from PyQt5.QtCore import QProcess import qutebrowser.utils.editor as editorutils - - -class ConfigStub: - - """Stub for editor.config. - - Attributes: - editor: The editor to return for general -> editor. - """ - - def __init__(self, editor): - self.editor = editor - - def get(self, sect, opt): - """Get the configured value for sect/opt.""" - if sect == 'general' and opt == 'editor': - return self.editor - else: - raise ValueError("Invalid option {} -> {}".format(sect, opt)) - - -class FakeQProcess: - - """QProcess stub. - - Gets some enum values from the real QProcess and uses mocks for signals. - """ - - NormalExit = QProcess.NormalExit - CrashExit = QProcess.CrashExit - - FailedToStart = QProcess.FailedToStart - Crashed = QProcess.Crashed - Timedout = QProcess.Timedout - WriteError = QProcess.WriteError - ReadError = QProcess.ReadError - UnknownError = QProcess.UnknownError - - def __init__(self, parent=None): # pylint: disable=unused-argument - self.finished = Mock() - self.error = Mock() - self.start = Mock() +from qutebrowser.test.stubs import ConfigStub, FakeQProcess def setUpModule(): @@ -81,7 +37,7 @@ def setUpModule(): editorutils.QProcess = FakeQProcess -class ArgTests(TestCase): +class ArgTests(unittest.TestCase): """Test argument handling. @@ -94,19 +50,21 @@ class ArgTests(TestCase): def test_simple_start_args(self): """Test starting editor without arguments.""" - editorutils.config = ConfigStub(editor=["bin"]) + editorutils.config = ConfigStub({'general': {'editor': ['bin']}}) self.editor.edit("") self.editor.proc.start.assert_called_with("bin", []) def test_start_args(self): """Test starting editor with static arguments.""" - editorutils.config = ConfigStub(editor=["bin", "foo", "bar"]) + editorutils.config = ConfigStub( + {'general': {'editor': ['bin', 'foo', 'bar']}}) self.editor.edit("") self.editor.proc.start.assert_called_with("bin", ["foo", "bar"]) def test_placeholder(self): """Test starting editor with placeholder argument.""" - editorutils.config = ConfigStub(editor=["bin", "foo", "{}", "bar"]) + editorutils.config = ConfigStub( + {'general': {'editor': ['bin', 'foo', '{}', 'bar']}}) self.editor.edit("") filename = self.editor.filename self.editor.proc.start.assert_called_with("bin", @@ -114,7 +72,8 @@ class ArgTests(TestCase): def test_in_arg_placeholder(self): """Test starting editor with placeholder argument inside argument.""" - editorutils.config = ConfigStub(editor=["bin", "foo{}bar"]) + editorutils.config = ConfigStub( + {'general': {'editor': ['bin', 'foo{}bar']}}) self.editor.edit("") self.editor.proc.start.assert_called_with("bin", ["foo{}bar"]) @@ -122,7 +81,7 @@ class ArgTests(TestCase): self.editor._cleanup() # pylint: disable=protected-access -class FileHandlingTests(TestCase): +class FileHandlingTests(unittest.TestCase): """Test creation/deletion of tempfile. @@ -132,7 +91,7 @@ class FileHandlingTests(TestCase): def setUp(self): self.editor = editorutils.ExternalEditor() - editorutils.config = ConfigStub(editor=[""]) + editorutils.config = ConfigStub({'general': {'editor': ['']}}) def test_file_handling_closed_ok(self): """Test file handling when closing with an exitstatus == 0.""" @@ -160,7 +119,7 @@ class FileHandlingTests(TestCase): self.assertFalse(os.path.exists(filename)) -class TextModifyTests(TestCase): +class TextModifyTests(unittest.TestCase): """Tests to test if the text gets saved/loaded correctly. @@ -171,7 +130,7 @@ class TextModifyTests(TestCase): def setUp(self): self.editor = editorutils.ExternalEditor() self.editor.editing_finished = Mock() - editorutils.config = ConfigStub(editor=[""]) + editorutils.config = ConfigStub({'general': {'editor': ['']}}) def _write(self, text): """Write a text to the file opened in the fake editor. @@ -227,7 +186,7 @@ class TextModifyTests(TestCase): self.editor.editing_finished.emit.assert_called_with("\u2601") -class ErrorMessageTests(TestCase): +class ErrorMessageTests(unittest.TestCase): """Test if statusbar error messages get emitted correctly. @@ -235,9 +194,11 @@ class ErrorMessageTests(TestCase): editor: The ExternalEditor instance to test. """ + # pylint: disable=maybe-no-member + def setUp(self): self.editor = editorutils.ExternalEditor() - editorutils.config = ConfigStub(editor=[""]) + editorutils.config = ConfigStub({'general': {'editor': ['']}}) def test_proc_error(self): """Test on_proc_error.""" diff --git a/qutebrowser/test/utils/test_log.py b/qutebrowser/test/utils/test_log.py index c6130d56f..da8a3b887 100644 --- a/qutebrowser/test/utils/test_log.py +++ b/qutebrowser/test/utils/test_log.py @@ -17,20 +17,17 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=protected-access,invalid-name - """Tests for qutebrowser.utils.log.""" import logging import unittest import argparse import sys -from unittest import TestCase import qutebrowser.utils.log as log -class BaseTest(TestCase): +class BaseTest(unittest.TestCase): """Base class for logging tests. @@ -39,6 +36,7 @@ class BaseTest(TestCase): def setUp(self): """Save the old logging configuration.""" + # pylint: disable=protected-access logger_dict = logging.getLogger().manager.loggerDict logging._acquireLock() try: @@ -57,6 +55,7 @@ class BaseTest(TestCase): def tearDown(self): """Restore the original logging configuration.""" + # pylint: disable=protected-access while self.root_logger.handlers: h = self.root_logger.handlers[0] self.root_logger.removeHandler(h) @@ -67,9 +66,9 @@ class BaseTest(TestCase): logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list - loggerDict = logging.getLogger().manager.loggerDict - loggerDict.clear() - loggerDict.update(self.saved_loggers) + logger_dict = logging.getLogger().manager.loggerDict + logger_dict.clear() + logger_dict.update(self.saved_loggers) logger_states = self.logger_states for name in self.logger_states: if logger_states[name] is not None: @@ -78,7 +77,7 @@ class BaseTest(TestCase): logging._releaseLock() -class LogFilterTests(TestCase): +class LogFilterTests(unittest.TestCase): """Tests for LogFilter. diff --git a/qutebrowser/test/utils/test_misc.py b/qutebrowser/test/utils/test_misc.py index f79bc63d0..a7ee3b91b 100644 --- a/qutebrowser/test/utils/test_misc.py +++ b/qutebrowser/test/utils/test_misc.py @@ -17,8 +17,6 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring,blacklisted-name,protected-access - """Tests for qutebrowser.utils.misc.""" import os @@ -28,7 +26,6 @@ import unittest import os.path import subprocess from tempfile import mkdtemp -from unittest import TestCase from PyQt5.QtCore import QStandardPaths, QCoreApplication from PyQt5.QtGui import QColor @@ -37,7 +34,7 @@ import qutebrowser.utils.misc as utils from qutebrowser.test.helpers import environ_set_temp -class ElidingTests(TestCase): +class ElidingTests(unittest.TestCase): """Test elide.""" @@ -61,7 +58,7 @@ class ElidingTests(TestCase): self.assertEqual(utils.elide('foobar', 3), 'fo' + self.ELLIPSIS) -class ReadFileTests(TestCase): +class ReadFileTests(unittest.TestCase): """Test read_file.""" @@ -71,7 +68,7 @@ class ReadFileTests(TestCase): self.assertEqual(content.splitlines()[0], "Hello World!") -class DottedGetattrTests(TestCase): +class DottedGetattrTests(unittest.TestCase): """Test dotted_getattr. @@ -106,7 +103,7 @@ class DottedGetattrTests(TestCase): _ = utils.dotted_getattr(self, 'test.foo.baz') -class SafeShlexSplitTests(TestCase): +class SafeShlexSplitTests(unittest.TestCase): """Test safe_shlex_split.""" @@ -141,7 +138,7 @@ class SafeShlexSplitTests(TestCase): self.assertEqual(items, ['one', 'two\\']) -class ShellEscapeTests(TestCase): +class ShellEscapeTests(unittest.TestCase): """Tests for shell_escape. @@ -204,7 +201,7 @@ class ShellEscapeTests(TestCase): sys.platform = self.platform -class GetStandardDirLinuxTests(TestCase): +class GetStandardDirLinuxTests(unittest.TestCase): """Tests for get_standard_dir under Linux. @@ -278,7 +275,7 @@ class GetStandardDirLinuxTests(TestCase): shutil.rmtree(self.temp_dir) -class GetStandardDirWindowsTests(TestCase): +class GetStandardDirWindowsTests(unittest.TestCase): """Tests for get_standard_dir under Windows. @@ -328,7 +325,7 @@ class GetStandardDirWindowsTests(TestCase): self.app.quit() -class InterpolateColorTests(TestCase): +class InterpolateColorTests(unittest.TestCase): """Tests for interpolate_color. @@ -416,7 +413,7 @@ class InterpolateColorTests(TestCase): self.assertEqual(color, expected) -class FormatSecondsTests(TestCase): +class FormatSecondsTests(unittest.TestCase): """Tests for format_seconds. @@ -444,7 +441,7 @@ class FormatSecondsTests(TestCase): self.assertEqual(utils.format_seconds(seconds), out, seconds) -class FormatSizeTests(TestCase): +class FormatSizeTests(unittest.TestCase): """Tests for format_size. diff --git a/qutebrowser/test/utils/test_misc_content_disposition.py b/qutebrowser/test/utils/test_misc_content_disposition.py index 7d77bf4c4..20e3b9e37 100644 --- a/qutebrowser/test/utils/test_misc_content_disposition.py +++ b/qutebrowser/test/utils/test_misc_content_disposition.py @@ -21,76 +21,19 @@ import os import unittest -from unittest import TestCase from unittest.mock import Mock import qutebrowser.utils.misc as utils +from qutebrowser.test.stubs import FakeNetworkReply DEFAULT_NAME = 'qutebrowser-download' -class FakeUrl: - - """QUrl stub which provides .path().""" - - def __init__(self, path=None): - self.path = Mock(return_value=path) - - -class FakeNetworkReply: - - """QNetworkReply stub which provides a Content-Disposition header.""" - - def __init__(self, content_disposition=None, url=None): - if url is None: - url = FakeUrl() - self._content_disposition = content_disposition - self.url = Mock(return_value=url) - - def hasRawHeader(self, name): - """Check if the reply has a certain header. - - Args: - name: The name of the header. - - Return: - True if the header is present, False if not. - - Raise: - ValueError: If a header other than Content-Disposition is - requested. - """ - if name == 'Content-Disposition': - return self._content_disposition is not None - else: - raise ValueError("Invalid header {}".format(name)) - - def rawHeader(self, name): - """Get the raw header data of a header. - - Args: - name: The name of the header. - - Return: - The header data, as ISO-8859-1 encoded bytes() object. - - Raise: - ValueError: If a header other than Content-Disposition is - requested. - """ - if name != 'Content-Disposition': - raise ValueError("Invalid header {}".format(name)) - cd = self._content_disposition - if cd is None: - raise ValueError("Content-Disposition is None!") - return cd.encode('iso-8859-1') - - # These test cases are based on http://greenbytes.de/tech/tc2231/ -class AttachmentTestCase(TestCase): +class AttachmentTestCase(unittest.TestCase): """Helper class with some convienence methods to check filenames.""" @@ -117,7 +60,7 @@ class AttachmentTestCase(TestCase): self.assertFalse(cd_inline) -class InlineTests(TestCase): +class InlineTests(unittest.TestCase): """Various tests relating to the "inline" disposition type. diff --git a/qutebrowser/test/utils/test_qt.py b/qutebrowser/test/utils/test_qt.py index 2b5edd833..5ca66615a 100644 --- a/qutebrowser/test/utils/test_qt.py +++ b/qutebrowser/test/utils/test_qt.py @@ -17,19 +17,16 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring,blacklisted-name,protected-access - """Tests for qutebrowser.utils.qt.""" import sys import argparse import unittest -from unittest import TestCase import qutebrowser.utils.qt as qt -class CheckOverflowTests(TestCase): +class CheckOverflowTests(unittest.TestCase): """Test check_overflow. @@ -83,7 +80,7 @@ class CheckOverflowTests(TestCase): "{}: {}".format(ctype, val)) -class GetQtArgsTests(TestCase): +class GetQtArgsTests(unittest.TestCase): """Tests for get_qt_args.""" diff --git a/qutebrowser/test/utils/test_readline.py b/qutebrowser/test/utils/test_readline.py index d13287ab6..2666a29bf 100644 --- a/qutebrowser/test/utils/test_readline.py +++ b/qutebrowser/test/utils/test_readline.py @@ -17,31 +17,19 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring - """Tests for qutebrowser.utils.readline.""" import inspect import unittest -from unittest import TestCase from unittest.mock import Mock from PyQt5.QtWidgets import QLineEdit import qutebrowser.utils.readline as readline +from qutebrowser.test.stubs import FakeQApplication -class FakeQApplication: - - """Stub to insert as QApplication module.""" - - def __init__(self, focus): - # pylint: disable=invalid-name - self.focusWidget = Mock(return_value=focus) - self.instance = Mock(return_value=self) - - -class NoneWidgetTests(TestCase): +class NoneWidgetTests(unittest.TestCase): """Tests when the focused widget is None.""" @@ -56,7 +44,7 @@ class NoneWidgetTests(TestCase): method() -class ReadlineBridgeTest(TestCase): +class ReadlineBridgeTest(unittest.TestCase): """Tests for readline bridge.""" @@ -71,34 +59,42 @@ class ReadlineBridgeTest(TestCase): self.qle.configure_mock(**{'selectedText.return_value': text}) def test_rl_backward_char(self): + """Test rl_backward_char.""" self.bridge.rl_backward_char() self.qle.cursorBackward.assert_called_with(False) def test_rl_forward_char(self): + """Test rl_forward_char.""" self.bridge.rl_forward_char() self.qle.cursorForward.assert_called_with(False) def test_rl_backward_word(self): + """Test rl_backward_word.""" self.bridge.rl_backward_word() self.qle.cursorWordBackward.assert_called_with(False) def test_rl_forward_word(self): + """Test rl_forward_word.""" self.bridge.rl_forward_word() self.qle.cursorWordForward.assert_called_with(False) def test_rl_beginning_of_line(self): + """Test rl_beginning_of_line.""" self.bridge.rl_beginning_of_line() self.qle.home.assert_called_with(False) def test_rl_end_of_line(self): + """Test rl_end_of_line.""" self.bridge.rl_end_of_line() self.qle.end.assert_called_with(False) def test_rl_delete_char(self): + """Test rl_delete_char.""" self.bridge.rl_delete_char() self.qle.del_.assert_called_with() def test_rl_backward_delete_char(self): + """Test rl_backward_delete_char.""" self.bridge.rl_backward_delete_char() self.qle.backspace.assert_called_with() diff --git a/qutebrowser/test/utils/test_url.py b/qutebrowser/test/utils/test_url.py index 8b036cf4f..73c6371d9 100644 --- a/qutebrowser/test/utils/test_url.py +++ b/qutebrowser/test/utils/test_url.py @@ -17,54 +17,26 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring,protected-access - """Tests for qutebrowser.utils.url.""" import unittest -from unittest import TestCase from PyQt5.QtCore import QUrl import qutebrowser.utils.url as urlutils +from qutebrowser.test.stubs import ConfigStub -class ConfigStub: - - """Stub which is used to mock out the config. - - Attributes: - _DATA: The config data to use - """ - - _DATA = { - 'general': {'auto-search': True}, - 'searchengines': { - 'test': 'http://www.qutebrowser.org/?q={}', - 'DEFAULT': 'http://www.example.com/?q={}', - }, - } - - class NoOptionError(Exception): - - """NoOptionError exception which does nothing.""" - - pass - - def get(self, section, option): - """Get a value from section/option. - - Raise: - NoOptionError if the option was not found. - """ - sect = self._DATA[section] - try: - return sect[option] - except KeyError: - raise self.NoOptionError +CONFIG = { + 'general': {'auto-search': True}, + 'searchengines': { + 'test': 'http://www.qutebrowser.org/?q={}', + 'DEFAULT': 'http://www.example.com/?q={}', + }, +} -class SpecialURLTests(TestCase): +class SpecialURLTests(unittest.TestCase): """Test is_special_url. @@ -97,7 +69,7 @@ class SpecialURLTests(TestCase): self.assertFalse(urlutils.is_special_url(u)) -class SearchUrlTests(TestCase): +class SearchUrlTests(unittest.TestCase): """Test _get_search_url. @@ -105,9 +77,11 @@ class SearchUrlTests(TestCase): config: The urlutils.config instance. """ + # pylint: disable=protected-access + def setUp(self): self.config = urlutils.config - urlutils.config = ConfigStub() + urlutils.config = ConfigStub(CONFIG) def test_default_engine(self): """Test default search engine.""" @@ -136,7 +110,7 @@ class SearchUrlTests(TestCase): urlutils.config = self.config -class IsUrlNaiveTests(TestCase): +class IsUrlNaiveTests(unittest.TestCase): """Tests for _is_url_naive. @@ -158,6 +132,8 @@ class IsUrlNaiveTests(TestCase): 'foo', ) + # pylint: disable=protected-access + def test_urls(self): """Test things which are URLs.""" for url in self.URLS: diff --git a/qutebrowser/test/utils/test_webelem.py b/qutebrowser/test/utils/test_webelem.py index 73b0aa28d..ce06bfecf 100644 --- a/qutebrowser/test/utils/test_webelem.py +++ b/qutebrowser/test/utils/test_webelem.py @@ -17,104 +17,18 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring,invalid-name - """Tests for the webelement utils.""" import unittest -from unittest import TestCase -from unittest.mock import Mock from PyQt5.QtCore import QRect, QPoint -from PyQt5.QtWebKit import QWebElement import qutebrowser.utils.webelem as webelem +from qutebrowser.test.stubs import (FakeWebElement, FakeWebFrame, + FakeChildrenFrame) -class FakeWebElement: - - """A stub for QWebElement.""" - - def __init__(self, geometry=None, frame=None, null=False, visibility='', - display='', attributes=None): - """Constructor. - - Args: - geometry: The geometry of the QWebElement as QRect. - frame: The QWebFrame the element is in. - null: Whether the element is null or not. - visibility: The CSS visibility style property calue. - display: The CSS display style property calue. - attributes: Boolean HTML attributes to be added. - - Raise: - ValueError if element is not null and geometry/frame are not given. - """ - self.geometry = Mock(return_value=geometry) - self.webFrame = Mock(return_value=frame) - self.isNull = Mock(return_value=null) - self._visibility = visibility - self._display = display - self._attributes = attributes - - def styleProperty(self, name, strategy): - """Return the CSS style property named name. - - Only display/visibility and ComputedStyle are simulated. - - Raise: - ValueError if strategy is not ComputedStyle or name is not - visibility/display. - """ - if strategy != QWebElement.ComputedStyle: - raise ValueError("styleProperty called with strategy != " - "ComputedStyle ({})!".format(strategy)) - if name == 'visibility': - return self._visibility - elif name == 'display': - return self._display - else: - raise ValueError("styleProperty called with unknown name " - "'{}'".format(name)) - - def hasAttribute(self, name): - """Check if the element has an attribute named name.""" - if self._attributes is None: - return False - else: - return name in self._attributes - - -class FakeWebFrame: - - """A stub for QWebFrame.""" - - def __init__(self, geometry, scroll=None, parent=None): - """Constructor. - - Args: - geometry: The geometry of the frame as QRect. - scroll: The scroll position as QPoint. - parent: The parent frame. - """ - if scroll is None: - scroll = QPoint(0, 0) - self.geometry = Mock(return_value=geometry) - self.scrollPosition = Mock(return_value=scroll) - self.parentFrame = Mock(return_value=parent) - - -class FakeChildrenFrame: - - """A stub for QWebFrame to test get_child_frames.""" - - def __init__(self, children=None): - if children is None: - children = [] - self.childFrames = Mock(return_value=children) - - -class IsVisibleInvalidTests(TestCase): +class IsVisibleInvalidTests(unittest.TestCase): """Tests for is_visible with invalid elements. @@ -156,7 +70,7 @@ class IsVisibleInvalidTests(TestCase): self.assertTrue(webelem.is_visible(elem, self.frame)) -class IsVisibleScrollTests(TestCase): +class IsVisibleScrollTests(unittest.TestCase): """Tests for is_visible when the frame is scrolled. @@ -178,7 +92,7 @@ class IsVisibleScrollTests(TestCase): self.assertTrue(webelem.is_visible(elem, self.frame)) -class IsVisibleCssTests(TestCase): +class IsVisibleCssTests(unittest.TestCase): """Tests for is_visible with CSS attributes. @@ -213,7 +127,7 @@ class IsVisibleCssTests(TestCase): self.assertFalse(webelem.is_visible(elem, self.frame)) -class IsVisibleIframeTests(TestCase): +class IsVisibleIframeTests(unittest.TestCase): """Tests for is_visible with a child frame. @@ -290,7 +204,7 @@ class IsVisibleIframeTests(TestCase): self.assertTrue(webelem.is_visible(self.elem4, self.frame)) -class IsWritableTests(TestCase): +class IsWritableTests(unittest.TestCase): """Check is_writable.""" @@ -310,7 +224,7 @@ class IsWritableTests(TestCase): self.assertFalse(webelem.is_writable(elem)) -class JavascriptEscapeTests(TestCase): +class JavascriptEscapeTests(unittest.TestCase): """Check javascript_escape. @@ -326,11 +240,12 @@ class JavascriptEscapeTests(TestCase): ) def test_fake_escape(self): + """Test javascript escaping.""" for before, after in self.STRINGS: self.assertEqual(webelem.javascript_escape(before), after) -class GetChildFramesTests(TestCase): +class GetChildFramesTests(unittest.TestCase): """Check get_child_frames.""" diff --git a/qutebrowser/test/utils/usertypes/test_enum.py b/qutebrowser/test/utils/usertypes/test_enum.py index 1ef472e80..707b967ee 100644 --- a/qutebrowser/test/utils/usertypes/test_enum.py +++ b/qutebrowser/test/utils/usertypes/test_enum.py @@ -17,17 +17,14 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=missing-docstring - """Tests for the Enum class.""" import unittest -from unittest import TestCase from qutebrowser.utils.usertypes import enum -class EnumTests(TestCase): +class EnumTests(unittest.TestCase): """Test simple enums. diff --git a/qutebrowser/test/utils/usertypes/test_neighborlist.py b/qutebrowser/test/utils/usertypes/test_neighborlist.py index bcc2ac165..c1af3a0e3 100644 --- a/qutebrowser/test/utils/usertypes/test_neighborlist.py +++ b/qutebrowser/test/utils/usertypes/test_neighborlist.py @@ -17,17 +17,14 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -# pylint: disable=protected-access,missing-docstring - """Tests for the NeighborList class.""" import unittest -from unittest import TestCase from qutebrowser.utils.usertypes import NeighborList -class InitTests(TestCase): +class InitTests(unittest.TestCase): """Just try to init some neighborlists. @@ -62,7 +59,7 @@ class InitTests(TestCase): self.assertNotIn(4, nl) -class DefaultTests(TestCase): +class DefaultTests(unittest.TestCase): """Test the default argument. @@ -86,7 +83,7 @@ class DefaultTests(TestCase): self.assertIsNone(nl.idx) -class EmptyTests(TestCase): +class EmptyTests(unittest.TestCase): """Tests with no items. @@ -118,7 +115,7 @@ class EmptyTests(TestCase): self.nl.getitem(1) -class ItemTests(TestCase): +class ItemTests(unittest.TestCase): """Tests with items. @@ -175,7 +172,7 @@ class ItemTests(TestCase): self.assertEqual(self.nl.idx, 0) -class OneTests(TestCase): +class OneTests(unittest.TestCase): """Tests with a list with only one item. @@ -183,6 +180,8 @@ class OneTests(TestCase): nl: The NeighborList we're testing. """ + # pylint: disable=protected-access + def setUp(self): self.nl = NeighborList([1], default=1) @@ -237,7 +236,7 @@ class OneTests(TestCase): self.assertEqual(self.nl.idx, 0) -class BlockTests(TestCase): +class BlockTests(unittest.TestCase): """Tests with mode=block. @@ -264,7 +263,7 @@ class BlockTests(TestCase): self.assertEqual(self.nl.idx, 4) -class WrapTests(TestCase): +class WrapTests(unittest.TestCase): """Tests with mode=wrap. @@ -291,7 +290,7 @@ class WrapTests(TestCase): self.assertEqual(self.nl.idx, 0) -class RaiseTests(TestCase): +class RaiseTests(unittest.TestCase): """Tests with mode=exception. @@ -320,7 +319,7 @@ class RaiseTests(TestCase): self.assertEqual(self.nl.idx, 4) -class SnapInTests(TestCase): +class SnapInTests(unittest.TestCase): """Tests for the fuzzyval/_snap_in features.