Merge pull request #16 from hackebrot/layout
Adopt test layout to pytest.
This commit is contained in:
commit
76651822bd
@ -40,6 +40,7 @@ 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_]*$
|
||||
docstring-min-length=2
|
||||
|
||||
[FORMAT]
|
||||
max-line-length=79
|
||||
|
@ -6,7 +6,7 @@ graft icons
|
||||
graft scripts/pylint_checkers
|
||||
graft doc/img
|
||||
graft misc
|
||||
include qutebrowser/test/testfile
|
||||
include qutebrowser/utils/testfile
|
||||
include qutebrowser/git-commit-id
|
||||
include COPYING doc/* README.asciidoc
|
||||
include qutebrowser.desktop
|
||||
@ -24,7 +24,7 @@ exclude scripts/segfault_test.sh
|
||||
exclude doc/notes
|
||||
exclude CONTRIBUTING.asciidoc
|
||||
recursive-exclude doc *.asciidoc
|
||||
prune test
|
||||
prune tests
|
||||
exclude qutebrowser.rcc
|
||||
exclude .coveragerc
|
||||
exclude .flake8
|
||||
|
@ -1,20 +0,0 @@
|
||||
# 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/>.
|
||||
|
||||
"""Tests for the qutebrowser.browser package."""
|
@ -1,20 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Tests for the qutebrowser.browser.http module."""
|
@ -1,140 +0,0 @@
|
||||
# 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/>.
|
||||
|
||||
"""Tests for webelement.tabhistory."""
|
||||
|
||||
import unittest
|
||||
|
||||
from PyQt5.QtCore import QUrl, QPoint
|
||||
|
||||
from qutebrowser.browser import tabhistory
|
||||
from qutebrowser.browser.tabhistory import TabHistoryItem as Item
|
||||
from qutebrowser.utils import qtutils
|
||||
from qutebrowser.test import helpers
|
||||
|
||||
|
||||
class SerializeHistoryTests(unittest.TestCase):
|
||||
|
||||
"""Tests for serialize()."""
|
||||
|
||||
def setUp(self):
|
||||
self.page = helpers.get_webpage()
|
||||
self.history = self.page.history()
|
||||
self.assertEqual(self.history.count(), 0)
|
||||
|
||||
self.items = [
|
||||
Item(QUrl('https://www.heise.de/'), QUrl('http://www.heise.de/'),
|
||||
'heise'),
|
||||
Item(QUrl('http://example.com/%E2%80%A6'),
|
||||
QUrl('http://example.com/%E2%80%A6'), 'percent', active=True),
|
||||
Item(QUrl('http://example.com/?foo=bar'),
|
||||
QUrl('http://original.url.example.com/'), 'arg',
|
||||
user_data={'foo': 23, 'bar': 42}),
|
||||
# From https://github.com/OtterBrowser/otter-browser/issues/709#issuecomment-74749471
|
||||
Item(QUrl('http://github.com/OtterBrowser/24/134/2344/otter-browser/issues/709/'),
|
||||
QUrl('http://github.com/OtterBrowser/24/134/2344/otter-browser/issues/709/'),
|
||||
'Page not found | github',
|
||||
user_data={'zoom': 149, 'scroll-pos': QPoint(0, 0)}),
|
||||
Item(QUrl('https://mail.google.com/mail/u/0/#label/some+label/234lkjsd0932lkjf884jqwerdf4'),
|
||||
QUrl('https://mail.google.com/mail/u/0/#label/some+label/234lkjsd0932lkjf884jqwerdf4'),
|
||||
'"some label" - email@gmail.com - Gmail"',
|
||||
user_data={'zoom': 120, 'scroll-pos': QPoint(0, 0)}),
|
||||
]
|
||||
stream, _data, self.user_data = tabhistory.serialize(self.items)
|
||||
qtutils.deserialize_stream(stream, self.history)
|
||||
|
||||
def test_count(self):
|
||||
"""Check if the history's count was loaded correctly."""
|
||||
with helpers.disable_logger('qt'):
|
||||
self.assertEqual(self.history.count(), len(self.items))
|
||||
|
||||
def test_valid(self):
|
||||
"""Check if all items are valid."""
|
||||
for i, _item in enumerate(self.items):
|
||||
self.assertTrue(self.history.itemAt(i).isValid())
|
||||
|
||||
def test_no_userdata(self):
|
||||
"""Check if all items have no user data."""
|
||||
for i, _item in enumerate(self.items):
|
||||
self.assertIsNone(self.history.itemAt(i).userData())
|
||||
|
||||
def test_userdata(self):
|
||||
"""Check if all user data has been restored to self.user_data."""
|
||||
for item, user_data in zip(self.items, self.user_data):
|
||||
self.assertEqual(user_data, item.user_data)
|
||||
|
||||
def test_currentitem(self):
|
||||
"""Check if the current item index was loaded correctly."""
|
||||
self.assertEqual(self.history.currentItemIndex(), 1)
|
||||
|
||||
def test_urls(self):
|
||||
"""Check if the URLs were loaded correctly."""
|
||||
for i, item in enumerate(self.items):
|
||||
with self.subTest(i=i, item=item):
|
||||
self.assertEqual(self.history.itemAt(i).url(), item.url)
|
||||
|
||||
def test_original_urls(self):
|
||||
"""Check if the original URLs were loaded correctly."""
|
||||
for i, item in enumerate(self.items):
|
||||
with self.subTest(i=i, item=item):
|
||||
self.assertEqual(self.history.itemAt(i).originalUrl(),
|
||||
item.original_url)
|
||||
|
||||
def test_titles(self):
|
||||
"""Check if the titles were loaded correctly."""
|
||||
for i, item in enumerate(self.items):
|
||||
with self.subTest(i=i, item=item):
|
||||
self.assertEqual(self.history.itemAt(i).title(), item.title)
|
||||
|
||||
|
||||
class SerializeHistorySpecialTests(unittest.TestCase):
|
||||
|
||||
"""Tests for serialize() without items set up in setUp."""
|
||||
|
||||
def setUp(self):
|
||||
self.page = helpers.get_webpage()
|
||||
self.history = self.page.history()
|
||||
self.assertEqual(self.history.count(), 0)
|
||||
|
||||
def test_no_active_item(self):
|
||||
"""Check tabhistory.serialize with no active item."""
|
||||
items = [Item(QUrl(), QUrl(), '')]
|
||||
with self.assertRaises(ValueError):
|
||||
tabhistory.serialize(items)
|
||||
|
||||
def test_two_active_items(self):
|
||||
"""Check tabhistory.serialize with two active items."""
|
||||
items = [Item(QUrl(), QUrl(), '', active=True),
|
||||
Item(QUrl(), QUrl(), ''),
|
||||
Item(QUrl(), QUrl(), '', active=True)]
|
||||
with self.assertRaises(ValueError):
|
||||
tabhistory.serialize(items)
|
||||
|
||||
def test_empty(self):
|
||||
"""Check tabhistory.serialize with no items."""
|
||||
items = []
|
||||
stream, _data, user_data = tabhistory.serialize(items)
|
||||
qtutils.deserialize_stream(stream, self.history)
|
||||
self.assertEqual(self.history.count(), 0)
|
||||
self.assertEqual(self.history.currentItemIndex(), 0)
|
||||
self.assertFalse(user_data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1 +0,0 @@
|
||||
"""Tests for qutebrowser.config."""
|
@ -1,109 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Helpers needed by tests."""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import contextlib
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtGui import QKeyEvent
|
||||
from PyQt5.QtWebKitWidgets import QWebPage
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager
|
||||
|
||||
|
||||
unicode_encode_err = UnicodeEncodeError('ascii', # codec
|
||||
'', # object
|
||||
0, # start
|
||||
2, # end
|
||||
'fake exception') # reason
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def environ_set_temp(env):
|
||||
"""Set temporary environment variables.
|
||||
|
||||
Args:
|
||||
env: A dictionary with name: value pairs.
|
||||
If value is None, the variable is temporarily deleted.
|
||||
"""
|
||||
old_env = {}
|
||||
|
||||
for name, value in env.items():
|
||||
try:
|
||||
old_env[name] = os.environ[name]
|
||||
except KeyError:
|
||||
pass
|
||||
if value is None:
|
||||
os.environ.pop(name, None)
|
||||
else:
|
||||
os.environ[name] = value
|
||||
|
||||
yield
|
||||
|
||||
for name, value in env.items():
|
||||
if name in old_env:
|
||||
os.environ[name] = old_env[name]
|
||||
elif value is not None:
|
||||
del os.environ[name]
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def disable_logger(name):
|
||||
"""Temporarily disable a logger."""
|
||||
logging.getLogger(name).propagate = False
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
logging.getLogger(name).propagate = True
|
||||
|
||||
|
||||
def fake_keyevent(key, modifiers=0, text=''):
|
||||
"""Generate a new fake QKeyPressEvent."""
|
||||
evtmock = mock.create_autospec(QKeyEvent, instance=True)
|
||||
evtmock.key.return_value = key
|
||||
evtmock.modifiers.return_value = modifiers
|
||||
evtmock.text.return_value = text
|
||||
return evtmock
|
||||
|
||||
|
||||
def get_webpage():
|
||||
"""Get a new QWebPage object."""
|
||||
page = QWebPage()
|
||||
nam = page.networkAccessManager()
|
||||
nam.setNetworkAccessible(QNetworkAccessManager.NotAccessible)
|
||||
return page
|
||||
|
||||
|
||||
class MessageModule:
|
||||
|
||||
"""A drop-in replacement for qutebrowser.utils.message."""
|
||||
|
||||
def error(self, _win_id, message, _immediately=False):
|
||||
"""Log an error to the message logger."""
|
||||
logging.getLogger('message').error(message)
|
||||
|
||||
def warning(self, _win_id, message, _immediately=False):
|
||||
"""Log a warning to the message logger."""
|
||||
logging.getLogger('message').warning(message)
|
||||
|
||||
def info(self, _win_id, message, _immediately=True):
|
||||
"""Log an info message to the message logger."""
|
||||
logging.getLogger('message').info(message)
|
@ -1 +0,0 @@
|
||||
"""Tests for qutebrowser.keyinput."""
|
@ -1,299 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
"""Tests for BaseKeyParser."""
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from qutebrowser.keyinput import basekeyparser
|
||||
from qutebrowser.test import stubs, helpers
|
||||
from qutebrowser.utils import objreg, log
|
||||
|
||||
|
||||
CONFIG = {'input': {'timeout': 100}}
|
||||
|
||||
|
||||
BINDINGS = {'test': {'<Ctrl-a>': 'ctrla',
|
||||
'a': 'a',
|
||||
'ba': 'ba',
|
||||
'ax': 'ax',
|
||||
'ccc': 'ccc'},
|
||||
'test2': {'foo': 'bar', '<Ctrl+X>': 'ctrlx'}}
|
||||
|
||||
|
||||
fake_keyconfig = mock.Mock(spec=['get_bindings_for'])
|
||||
fake_keyconfig.get_bindings_for.side_effect = lambda s: BINDINGS[s]
|
||||
|
||||
|
||||
class SplitCountTests(unittest.TestCase):
|
||||
|
||||
"""Test the _split_count method.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser we're testing.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_count=True)
|
||||
|
||||
def test_onlycount(self):
|
||||
"""Test split_count with only a count."""
|
||||
self.kp._keystring = '10'
|
||||
self.assertEqual(self.kp._split_count(), (10, ''))
|
||||
|
||||
def test_normalcount(self):
|
||||
"""Test split_count with count and text."""
|
||||
self.kp._keystring = '10foo'
|
||||
self.assertEqual(self.kp._split_count(), (10, 'foo'))
|
||||
|
||||
def test_minuscount(self):
|
||||
"""Test split_count with a negative count."""
|
||||
self.kp._keystring = '-1foo'
|
||||
self.assertEqual(self.kp._split_count(), (None, '-1foo'))
|
||||
|
||||
def test_expcount(self):
|
||||
"""Test split_count with an exponential count."""
|
||||
self.kp._keystring = '10e4foo'
|
||||
self.assertEqual(self.kp._split_count(), (10, 'e4foo'))
|
||||
|
||||
def test_nocount(self):
|
||||
"""Test split_count with only a command."""
|
||||
self.kp._keystring = 'foo'
|
||||
self.assertEqual(self.kp._split_count(), (None, 'foo'))
|
||||
|
||||
def test_nosupport(self):
|
||||
"""Test split_count with a count when counts aren't supported."""
|
||||
self.kp._supports_count = False
|
||||
self.kp._keystring = '10foo'
|
||||
self.assertEqual(self.kp._split_count(), (None, '10foo'))
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
class ReadConfigTests(unittest.TestCase):
|
||||
|
||||
"""Test reading the config."""
|
||||
|
||||
def setUp(self):
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
|
||||
def tearDown(self):
|
||||
objreg.delete('key-config')
|
||||
|
||||
def test_read_config_invalid(self):
|
||||
"""Test reading config without setting it before."""
|
||||
kp = basekeyparser.BaseKeyParser(0)
|
||||
with self.assertRaises(ValueError):
|
||||
kp.read_config()
|
||||
|
||||
def test_read_config_valid(self):
|
||||
"""Test reading config."""
|
||||
kp = basekeyparser.BaseKeyParser(0, supports_count=True,
|
||||
supports_chains=True)
|
||||
kp.read_config('test')
|
||||
self.assertIn('ccc', kp.bindings)
|
||||
self.assertIn('ctrl+a', kp.special_bindings)
|
||||
kp.read_config('test2')
|
||||
self.assertNotIn('ccc', kp.bindings)
|
||||
self.assertNotIn('ctrl+a', kp.special_bindings)
|
||||
self.assertIn('foo', kp.bindings)
|
||||
self.assertIn('ctrl+x', kp.special_bindings)
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
class SpecialKeysTests(unittest.TestCase):
|
||||
|
||||
"""Check execute() with special keys.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser to be tested.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
self.kp = basekeyparser.BaseKeyParser(0)
|
||||
self.kp.execute = mock.Mock()
|
||||
with self.assertLogs(log.keyboard, logging.WARNING):
|
||||
# Ignoring keychain 'ccc' in mode 'test' because keychains are not
|
||||
# supported there.
|
||||
self.kp.read_config('test')
|
||||
|
||||
def tearDown(self):
|
||||
objreg.delete('key-config')
|
||||
|
||||
def test_valid_key(self):
|
||||
"""Test a valid special keyevent."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, Qt.ControlModifier))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, Qt.ControlModifier))
|
||||
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
|
||||
|
||||
def test_invalid_key(self):
|
||||
"""Test an invalid special keyevent."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, (Qt.ControlModifier |
|
||||
Qt.AltModifier)))
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
|
||||
def test_keychain(self):
|
||||
"""Test a keychain."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A))
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
class KeyChainTests(unittest.TestCase):
|
||||
|
||||
"""Test execute() with keychain support.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser to be tested.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up mocks and read the test config."""
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
|
||||
supports_count=False)
|
||||
self.kp.execute = mock.Mock()
|
||||
self.kp.read_config('test')
|
||||
|
||||
def tearDown(self):
|
||||
objreg.delete('key-config')
|
||||
|
||||
def test_valid_special_key(self):
|
||||
"""Test valid special key."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, Qt.ControlModifier))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, Qt.ControlModifier))
|
||||
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_invalid_special_key(self):
|
||||
"""Test invalid special key."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, (Qt.ControlModifier |
|
||||
Qt.AltModifier)))
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_keychain(self):
|
||||
"""Test valid keychain."""
|
||||
# Press 'x' which is ignored because of no match
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x'))
|
||||
# Then start the real chain
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.config',
|
||||
new=stubs.ConfigStub(CONFIG))
|
||||
def test_ambiguous_keychain(self):
|
||||
"""Test ambiguous keychain."""
|
||||
timer = self.kp._ambiguous_timer
|
||||
self.assertFalse(timer.isActive())
|
||||
# We start with 'a' where the keychain gives us an ambiguous result.
|
||||
# Then we check if the timer has been set up correctly
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
self.assertTrue(timer.isSingleShot())
|
||||
self.assertEqual(timer.interval(), 100)
|
||||
self.assertTrue(timer.isActive())
|
||||
# Now we type an 'x' and check 'ax' has been executed and the timer
|
||||
# stopped.
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x'))
|
||||
self.kp.execute.assert_called_once_with('ax', self.kp.Type.chain, None)
|
||||
self.assertFalse(timer.isActive())
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_invalid_keychain(self):
|
||||
"""Test invalid keychain."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_C, text='c'))
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
class CountTests(unittest.TestCase):
|
||||
|
||||
"""Test execute() with counts."""
|
||||
|
||||
def setUp(self):
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
|
||||
supports_count=True)
|
||||
self.kp.execute = mock.Mock()
|
||||
self.kp.read_config('test')
|
||||
|
||||
def test_no_count(self):
|
||||
"""Test with no count added."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_count_0(self):
|
||||
"""Test with count=0."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_0, text='0'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 0)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_count_42(self):
|
||||
"""Test with count=42."""
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='4'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='2'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 42)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def test_count_42_invalid(self):
|
||||
"""Test with count=42 and invalid command."""
|
||||
# Invalid call with ccx gets ignored
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='4'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='2'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='c'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='x'))
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
# Valid call with ccc gets the correct count
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_4, text='2'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_2, text='3'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='c'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='c'))
|
||||
self.kp.execute.assert_called_once_with('ccc', self.kp.Type.chain, 23)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
|
||||
def tearDown(self):
|
||||
objreg.global_registry.clear()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,20 +0,0 @@
|
||||
# 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/>.
|
||||
|
||||
"""The qutebrowser test suite."""
|
@ -1,84 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Test test helpers."""
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from qutebrowser.test import helpers
|
||||
|
||||
|
||||
class TestEnvironSetTemp(unittest.TestCase):
|
||||
|
||||
"""Test the environ_set_temp helper."""
|
||||
|
||||
def test_environ_set(self):
|
||||
"""Test environ_set_temp with something which was set already."""
|
||||
os.environ['QUTEBROWSER_ENVIRON_TEST'] = 'oldval'
|
||||
with helpers.environ_set_temp({'QUTEBROWSER_ENVIRON_TEST': 'newval'}):
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval')
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'oldval')
|
||||
|
||||
def test_environ_unset(self):
|
||||
"""Test environ_set_temp with something which wasn't set yet."""
|
||||
with helpers.environ_set_temp({'QUTEBROWSER_ENVIRON_TEST': 'newval'}):
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'newval')
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ)
|
||||
|
||||
def test_environ_multiple(self):
|
||||
"""Test environ_set_temp with multiple values."""
|
||||
os.environ['QUTEBROWSER_ENVIRON_TEST_1'] = 'oldval_1'
|
||||
os.environ['QUTEBROWSER_ENVIRON_TEST_3'] = 'oldval_3'
|
||||
env = {
|
||||
'QUTEBROWSER_ENVIRON_TEST_1': 'newval_1',
|
||||
'QUTEBROWSER_ENVIRON_TEST_2': 'newval_2',
|
||||
'QUTEBROWSER_ENVIRON_TEST_3': None,
|
||||
}
|
||||
with helpers.environ_set_temp(env):
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST_1'],
|
||||
'newval_1')
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST_2'],
|
||||
'newval_2')
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST_3', os.environ)
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST_1'], 'oldval_1')
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST_2', os.environ)
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST_3'], 'oldval_3')
|
||||
|
||||
def test_environ_none_set(self):
|
||||
"""Test environ_set_temp with something which was set already."""
|
||||
os.environ['QUTEBROWSER_ENVIRON_TEST'] = 'oldval'
|
||||
with helpers.environ_set_temp({'QUTEBROWSER_ENVIRON_TEST': None}):
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ)
|
||||
self.assertEqual(os.environ['QUTEBROWSER_ENVIRON_TEST'], 'oldval')
|
||||
|
||||
def test_environ_none_unset(self):
|
||||
"""Test environ_set_temp with something which wasn't set yet."""
|
||||
with helpers.environ_set_temp({'QUTEBROWSER_ENVIRON_TEST': None}):
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ)
|
||||
self.assertNotIn('QUTEBROWSER_ENVIRON_TEST', os.environ)
|
||||
|
||||
def tearDown(self):
|
||||
if 'QUTEBROWSER_ENVIRON_TEST' in os.environ:
|
||||
# if some test failed
|
||||
del os.environ['QUTEBROWSER_ENVIRON_TEST']
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,107 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Test test stubs."""
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from qutebrowser.test import stubs
|
||||
|
||||
|
||||
class TestFakeTimer(unittest.TestCase):
|
||||
|
||||
"""Test FakeTimer."""
|
||||
|
||||
def setUp(self):
|
||||
self.timer = stubs.FakeTimer()
|
||||
|
||||
def test_timeout(self):
|
||||
"""Test whether timeout calls the functions."""
|
||||
func = mock.Mock()
|
||||
func2 = mock.Mock()
|
||||
self.timer.timeout.connect(func)
|
||||
self.timer.timeout.connect(func2)
|
||||
self.assertFalse(func.called)
|
||||
self.assertFalse(func2.called)
|
||||
self.timer.timeout.emit()
|
||||
func.assert_called_once_with()
|
||||
func2.assert_called_once_with()
|
||||
|
||||
def test_disconnect_all(self):
|
||||
"""Test disconnect without arguments."""
|
||||
func = mock.Mock()
|
||||
self.timer.timeout.connect(func)
|
||||
self.timer.timeout.disconnect()
|
||||
self.timer.timeout.emit()
|
||||
self.assertFalse(func.called)
|
||||
|
||||
def test_disconnect_one(self):
|
||||
"""Test disconnect with a single argument."""
|
||||
func = mock.Mock()
|
||||
self.timer.timeout.connect(func)
|
||||
self.timer.timeout.disconnect(func)
|
||||
self.timer.timeout.emit()
|
||||
self.assertFalse(func.called)
|
||||
|
||||
def test_disconnect_all_invalid(self):
|
||||
"""Test disconnecting with no connections."""
|
||||
with self.assertRaises(TypeError):
|
||||
self.timer.timeout.disconnect()
|
||||
|
||||
def test_disconnect_one_invalid(self):
|
||||
"""Test disconnecting with an invalid connection."""
|
||||
func1 = mock.Mock()
|
||||
func2 = mock.Mock()
|
||||
self.timer.timeout.connect(func1)
|
||||
with self.assertRaises(TypeError):
|
||||
self.timer.timeout.disconnect(func2)
|
||||
self.assertFalse(func1.called)
|
||||
self.assertFalse(func2.called)
|
||||
self.timer.timeout.emit()
|
||||
func1.assert_called_once_with()
|
||||
|
||||
def test_singleshot(self):
|
||||
"""Test setting singleShot."""
|
||||
self.assertFalse(self.timer.singleShot())
|
||||
self.timer.setSingleShot(True)
|
||||
self.assertTrue(self.timer.singleShot())
|
||||
self.timer.start()
|
||||
self.assertTrue(self.timer.isActive())
|
||||
self.timer.timeout.emit()
|
||||
self.assertFalse(self.timer.isActive())
|
||||
|
||||
def test_active(self):
|
||||
"""Test isActive."""
|
||||
self.assertFalse(self.timer.isActive())
|
||||
self.timer.start()
|
||||
self.assertTrue(self.timer.isActive())
|
||||
self.timer.stop()
|
||||
self.assertFalse(self.timer.isActive())
|
||||
|
||||
def test_interval(self):
|
||||
"""Test setting an interval."""
|
||||
self.assertEqual(self.timer.interval(), 0)
|
||||
self.timer.setInterval(1000)
|
||||
self.assertEqual(self.timer.interval(), 1000)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -1,138 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Tests for qutebrowser.utils.standarddir."""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import shutil
|
||||
import unittest
|
||||
import tempfile
|
||||
|
||||
from qutebrowser.utils import standarddir
|
||||
from qutebrowser.test import helpers, qApp
|
||||
|
||||
|
||||
class GetStandardDirLinuxTests(unittest.TestCase):
|
||||
|
||||
"""Tests for standarddir under Linux.
|
||||
|
||||
Attributes:
|
||||
temp_dir: A temporary directory.
|
||||
old_name: The old applicationName.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.temp_dir = tempfile.mkdtemp()
|
||||
self.old_name = qApp.applicationName()
|
||||
qApp.setApplicationName('qutebrowser')
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_data_explicit(self):
|
||||
"""Test data dir with XDG_DATA_HOME explicitly set."""
|
||||
with helpers.environ_set_temp({'XDG_DATA_HOME': self.temp_dir}):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, 'qutebrowser')
|
||||
self.assertEqual(standarddir.data(), expected)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_config_explicit(self):
|
||||
"""Test config dir with XDG_CONFIG_HOME explicitly set."""
|
||||
with helpers.environ_set_temp({'XDG_CONFIG_HOME': self.temp_dir}):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, 'qutebrowser')
|
||||
self.assertEqual(standarddir.config(), expected)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_cache_explicit(self):
|
||||
"""Test cache dir with XDG_CACHE_HOME explicitly set."""
|
||||
with helpers.environ_set_temp({'XDG_CACHE_HOME': self.temp_dir}):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, 'qutebrowser')
|
||||
self.assertEqual(standarddir.cache(), expected)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_data(self):
|
||||
"""Test data dir with XDG_DATA_HOME not set."""
|
||||
env = {'HOME': self.temp_dir, 'XDG_DATA_HOME': None}
|
||||
with helpers.environ_set_temp(env):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, '.local', 'share',
|
||||
'qutebrowser')
|
||||
self.assertEqual(standarddir.data(), expected)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_config(self):
|
||||
"""Test config dir with XDG_CONFIG_HOME not set."""
|
||||
env = {'HOME': self.temp_dir, 'XDG_CONFIG_HOME': None}
|
||||
with helpers.environ_set_temp(env):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, '.config', 'qutebrowser')
|
||||
self.assertEqual(standarddir.config(), expected)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("linux"), "requires Linux")
|
||||
def test_cache(self):
|
||||
"""Test cache dir with XDG_CACHE_HOME not set."""
|
||||
env = {'HOME': self.temp_dir, 'XDG_CACHE_HOME': None}
|
||||
with helpers.environ_set_temp(env):
|
||||
standarddir.init(None)
|
||||
expected = os.path.join(self.temp_dir, '.cache', 'qutebrowser')
|
||||
self.assertEqual(standarddir.cache(), expected)
|
||||
|
||||
def tearDown(self):
|
||||
qApp.setApplicationName(self.old_name)
|
||||
shutil.rmtree(self.temp_dir)
|
||||
|
||||
|
||||
class GetStandardDirWindowsTests(unittest.TestCase):
|
||||
|
||||
"""Tests for standarddir under Windows.
|
||||
|
||||
Attributes:
|
||||
old_name: The old applicationName.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.old_name = qApp.applicationName()
|
||||
# We can't store the files in a temp dir, so we don't chose qutebrowser
|
||||
qApp.setApplicationName('qutebrowser_test')
|
||||
standarddir.init(None)
|
||||
|
||||
def tearDown(self):
|
||||
qApp.setApplicationName(self.old_name)
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
|
||||
def test_data(self):
|
||||
"""Test data dir."""
|
||||
self.assertEqual(standarddir.data().split(os.sep)[-2:],
|
||||
['qutebrowser_test', 'data'], standarddir.data())
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
|
||||
def test_config(self):
|
||||
"""Test config dir."""
|
||||
self.assertEqual(standarddir.config().split(os.sep)[-1],
|
||||
'qutebrowser_test',
|
||||
standarddir.config())
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
|
||||
def test_cache(self):
|
||||
"""Test cache dir."""
|
||||
self.assertEqual(standarddir.cache().split(os.sep)[-2:],
|
||||
['qutebrowser_test', 'cache'], standarddir.cache())
|
@ -1,20 +0,0 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Tests for qutebrowser.utils.usertype."""
|
@ -76,7 +76,7 @@ def check_spelling(target):
|
||||
# Words which look better when splitted, but might need some fine tuning.
|
||||
words |= {'keystrings', 'webelements', 'mouseevent', 'keysequence',
|
||||
'normalmode', 'eventloops', 'sizehint', 'statemachine',
|
||||
'metaobject', 'logrecord', 'monkeypatch', 'filetype'}
|
||||
'metaobject', 'logrecord', 'filetype'}
|
||||
|
||||
seen = collections.defaultdict(list)
|
||||
try:
|
||||
|
60
scripts/run_pylint_on_tests.py
Normal file
60
scripts/run_pylint_on_tests.py
Normal file
@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Run pylint on tests.
|
||||
|
||||
This is needed because pylint can't check a folder which isn't a package:
|
||||
https://bitbucket.org/logilab/pylint/issue/512/
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
import subprocess
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
|
||||
|
||||
from scripts import utils
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point.
|
||||
|
||||
Return:
|
||||
The pylint exit status.
|
||||
"""
|
||||
utils.change_cwd()
|
||||
files = []
|
||||
for dirpath, _dirnames, filenames in os.walk('tests'):
|
||||
for fn in filenames:
|
||||
if os.path.splitext(fn)[1] == '.py':
|
||||
files.append(os.path.join(dirpath, fn))
|
||||
disabled = ['attribute-defined-outside-init', 'redefined-outer-name',
|
||||
'unused-argument']
|
||||
no_docstring_rgx = ['^__.*__$', '^setup$']
|
||||
args = (['--disable={}'.format(','.join(disabled)),
|
||||
'--no-docstring-rgx=({})'.format('|'.join(no_docstring_rgx))] +
|
||||
sys.argv[1:] + files)
|
||||
ret = subprocess.call(['pylint'] + args)
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
File diff suppressed because it is too large
Load Diff
@ -23,46 +23,39 @@ Note that tests for parse_content_disposition are in their own
|
||||
test_content_disposition.py file.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from qutebrowser.browser import http
|
||||
from qutebrowser.test import stubs
|
||||
|
||||
|
||||
class ParseContentTypeTests(unittest.TestCase):
|
||||
class TestParseContentType:
|
||||
|
||||
"""Test for parse_content_type."""
|
||||
|
||||
def test_not_existing(self):
|
||||
def test_not_existing(self, stubs):
|
||||
"""Test without any Content-Type header."""
|
||||
reply = stubs.FakeNetworkReply()
|
||||
mimetype, rest = http.parse_content_type(reply)
|
||||
self.assertIsNone(mimetype)
|
||||
self.assertIsNone(rest)
|
||||
assert mimetype is None
|
||||
assert rest is None
|
||||
|
||||
def test_mimetype(self):
|
||||
def test_mimetype(self, stubs):
|
||||
"""Test with simple Content-Type header."""
|
||||
reply = stubs.FakeNetworkReply(
|
||||
headers={'Content-Type': 'image/example'})
|
||||
mimetype, rest = http.parse_content_type(reply)
|
||||
self.assertEqual(mimetype, 'image/example')
|
||||
self.assertIsNone(rest)
|
||||
assert mimetype == 'image/example'
|
||||
assert rest is None
|
||||
|
||||
def test_empty(self):
|
||||
def test_empty(self, stubs):
|
||||
"""Test with empty Content-Type header."""
|
||||
reply = stubs.FakeNetworkReply(headers={'Content-Type': ''})
|
||||
mimetype, rest = http.parse_content_type(reply)
|
||||
self.assertEqual(mimetype, '')
|
||||
self.assertIsNone(rest)
|
||||
assert mimetype == ''
|
||||
assert rest is None
|
||||
|
||||
def test_additional(self):
|
||||
def test_additional(self, stubs):
|
||||
"""Test with Content-Type header with additional informations."""
|
||||
reply = stubs.FakeNetworkReply(
|
||||
headers={'Content-Type': 'image/example; encoding=UTF-8'})
|
||||
mimetype, rest = http.parse_content_type(reply)
|
||||
self.assertEqual(mimetype, 'image/example')
|
||||
self.assertEqual(rest, ' encoding=UTF-8')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert mimetype == 'image/example'
|
||||
assert rest == ' encoding=UTF-8'
|
139
tests/browser/test_tabhistory.py
Normal file
139
tests/browser/test_tabhistory.py
Normal file
@ -0,0 +1,139 @@
|
||||
# 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/>.
|
||||
|
||||
"""Tests for webelement.tabhistory."""
|
||||
|
||||
from PyQt5.QtCore import QUrl, QPoint
|
||||
import pytest
|
||||
|
||||
from qutebrowser.browser import tabhistory
|
||||
from qutebrowser.browser.tabhistory import TabHistoryItem as Item
|
||||
from qutebrowser.utils import qtutils
|
||||
|
||||
|
||||
class TestSerializeHistory:
|
||||
|
||||
"""Tests for serialize()."""
|
||||
|
||||
ITEMS = [
|
||||
Item(QUrl('https://www.heise.de/'), QUrl('http://www.heise.de/'),
|
||||
'heise'),
|
||||
Item(QUrl('http://example.com/%E2%80%A6'),
|
||||
QUrl('http://example.com/%E2%80%A6'), 'percent', active=True),
|
||||
Item(QUrl('http://example.com/?foo=bar'),
|
||||
QUrl('http://original.url.example.com/'), 'arg',
|
||||
user_data={'foo': 23, 'bar': 42}),
|
||||
# From https://github.com/OtterBrowser/otter-browser/issues/709#issuecomment-74749471
|
||||
Item(
|
||||
QUrl('http://github.com/OtterBrowser/24/134/2344/otter-browser/'
|
||||
'issues/709/'),
|
||||
QUrl('http://github.com/OtterBrowser/24/134/2344/otter-browser/'
|
||||
'issues/709/'),
|
||||
'Page not found | github',
|
||||
user_data={'zoom': 149, 'scroll-pos': QPoint(0, 0)}),
|
||||
Item(
|
||||
QUrl('https://mail.google.com/mail/u/0/#label/some+label/'
|
||||
'234lkjsd0932lkjf884jqwerdf4'),
|
||||
QUrl('https://mail.google.com/mail/u/0/#label/some+label/'
|
||||
'234lkjsd0932lkjf884jqwerdf4'),
|
||||
'"some label" - email@gmail.com - Gmail"',
|
||||
user_data={'zoom': 120, 'scroll-pos': QPoint(0, 0)}),
|
||||
]
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, webpage):
|
||||
self.page = webpage
|
||||
self.history = self.page.history()
|
||||
assert self.history.count() == 0
|
||||
|
||||
stream, _data, self.user_data = tabhistory.serialize(self.ITEMS)
|
||||
qtutils.deserialize_stream(stream, self.history)
|
||||
|
||||
def test_count(self):
|
||||
"""Check if the history's count was loaded correctly."""
|
||||
assert self.history.count() == len(self.ITEMS)
|
||||
|
||||
@pytest.mark.parametrize('i', range(len(ITEMS)))
|
||||
def test_valid(self, i):
|
||||
"""Check if all items are valid."""
|
||||
assert self.history.itemAt(i).isValid()
|
||||
|
||||
@pytest.mark.parametrize('i', range(len(ITEMS)))
|
||||
def test_no_userdata(self, i):
|
||||
"""Check if all items have no user data."""
|
||||
assert self.history.itemAt(i).userData() is None
|
||||
|
||||
def test_userdata(self):
|
||||
"""Check if all user data has been restored to self.user_data."""
|
||||
userdata_items = [item.user_data for item in self.ITEMS]
|
||||
assert userdata_items == self.user_data
|
||||
|
||||
def test_currentitem(self):
|
||||
"""Check if the current item index was loaded correctly."""
|
||||
assert self.history.currentItemIndex() == 1
|
||||
|
||||
@pytest.mark.parametrize('i, item', enumerate(ITEMS))
|
||||
def test_urls(self, i, item):
|
||||
"""Check if the URLs were loaded correctly."""
|
||||
assert self.history.itemAt(i).url() == item.url
|
||||
|
||||
@pytest.mark.parametrize('i, item', enumerate(ITEMS))
|
||||
def test_original_urls(self, i, item):
|
||||
"""Check if the original URLs were loaded correctly."""
|
||||
assert self.history.itemAt(i).originalUrl() == item.original_url
|
||||
|
||||
@pytest.mark.parametrize('i, item', enumerate(ITEMS))
|
||||
def test_titles(self, i, item):
|
||||
"""Check if the titles were loaded correctly."""
|
||||
assert self.history.itemAt(i).title() == item.title
|
||||
|
||||
|
||||
class TestSerializeHistorySpecial:
|
||||
|
||||
"""Tests for serialize() without items set up in setup."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, webpage):
|
||||
"""Set up the initial QWebPage for each test."""
|
||||
self.page = webpage
|
||||
self.history = self.page.history()
|
||||
assert self.history.count() == 0
|
||||
|
||||
def test_no_active_item(self):
|
||||
"""Check tabhistory.serialize with no active item."""
|
||||
items = [Item(QUrl(), QUrl(), '')]
|
||||
with pytest.raises(ValueError):
|
||||
tabhistory.serialize(items)
|
||||
|
||||
def test_two_active_items(self):
|
||||
"""Check tabhistory.serialize with two active items."""
|
||||
items = [Item(QUrl(), QUrl(), '', active=True),
|
||||
Item(QUrl(), QUrl(), ''),
|
||||
Item(QUrl(), QUrl(), '', active=True)]
|
||||
with pytest.raises(ValueError):
|
||||
tabhistory.serialize(items)
|
||||
|
||||
def test_empty(self):
|
||||
"""Check tabhistory.serialize with no items."""
|
||||
items = []
|
||||
stream, _data, user_data = tabhistory.serialize(items)
|
||||
qtutils.deserialize_stream(stream, self.history)
|
||||
assert self.history.count() == 0
|
||||
assert self.history.currentItemIndex() == 0
|
||||
assert not user_data
|
@ -21,15 +21,14 @@
|
||||
|
||||
"""Tests for the webelement utils."""
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
import collections.abc
|
||||
|
||||
from PyQt5.QtCore import QRect, QPoint
|
||||
from PyQt5.QtWebKit import QWebElement
|
||||
import pytest
|
||||
|
||||
from qutebrowser.browser import webelem
|
||||
from qutebrowser.test import stubs
|
||||
|
||||
|
||||
def get_webelem(geometry=None, frame=None, null=False, visibility='',
|
||||
@ -87,17 +86,17 @@ def get_webelem(geometry=None, frame=None, null=False, visibility='',
|
||||
return wrapped
|
||||
|
||||
|
||||
class WebElementWrapperTests(unittest.TestCase):
|
||||
class TestWebElementWrapper:
|
||||
|
||||
"""Test WebElementWrapper."""
|
||||
|
||||
def test_nullelem(self):
|
||||
"""Test __init__ with a null element."""
|
||||
with self.assertRaises(webelem.IsNullError):
|
||||
with pytest.raises(webelem.IsNullError):
|
||||
get_webelem(null=True)
|
||||
|
||||
|
||||
class IsVisibleInvalidTests(unittest.TestCase):
|
||||
class TestIsVisibleInvalid:
|
||||
|
||||
"""Tests for is_visible with invalid elements.
|
||||
|
||||
@ -105,7 +104,8 @@ class IsVisibleInvalidTests(unittest.TestCase):
|
||||
frame: The FakeWebFrame we're using to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, stubs):
|
||||
self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100))
|
||||
|
||||
def test_nullelem(self):
|
||||
@ -116,15 +116,15 @@ class IsVisibleInvalidTests(unittest.TestCase):
|
||||
"""
|
||||
elem = get_webelem()
|
||||
elem._elem.isNull.return_value = True
|
||||
with self.assertRaises(webelem.IsNullError):
|
||||
with pytest.raises(webelem.IsNullError):
|
||||
elem.is_visible(self.frame)
|
||||
|
||||
def test_invalid_invisible(self):
|
||||
"""Test elements with an invalid geometry which are invisible."""
|
||||
elem = get_webelem(QRect(0, 0, 0, 0), self.frame)
|
||||
self.assertFalse(elem.geometry().isValid())
|
||||
self.assertEqual(elem.geometry().x(), 0)
|
||||
self.assertFalse(elem.is_visible(self.frame))
|
||||
assert not elem.geometry().isValid()
|
||||
assert elem.geometry().x() == 0
|
||||
assert not elem.is_visible(self.frame)
|
||||
|
||||
def test_invalid_visible(self):
|
||||
"""Test elements with an invalid geometry which are visible.
|
||||
@ -133,11 +133,11 @@ class IsVisibleInvalidTests(unittest.TestCase):
|
||||
which *are* visible, but don't have a valid geometry.
|
||||
"""
|
||||
elem = get_webelem(QRect(10, 10, 0, 0), self.frame)
|
||||
self.assertFalse(elem.geometry().isValid())
|
||||
self.assertTrue(elem.is_visible(self.frame))
|
||||
assert not elem.geometry().isValid()
|
||||
assert elem.is_visible(self.frame)
|
||||
|
||||
|
||||
class IsVisibleScrollTests(unittest.TestCase):
|
||||
class TestIsVisibleScroll:
|
||||
|
||||
"""Tests for is_visible when the frame is scrolled.
|
||||
|
||||
@ -145,22 +145,23 @@ class IsVisibleScrollTests(unittest.TestCase):
|
||||
frame: The FakeWebFrame we're using to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, stubs):
|
||||
self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100),
|
||||
scroll=QPoint(10, 10))
|
||||
|
||||
def test_invisible(self):
|
||||
"""Test elements which should be invisible due to scrolling."""
|
||||
elem = get_webelem(QRect(5, 5, 4, 4), self.frame)
|
||||
self.assertFalse(elem.is_visible(self.frame))
|
||||
assert not elem.is_visible(self.frame)
|
||||
|
||||
def test_visible(self):
|
||||
"""Test elements which still should be visible after scrolling."""
|
||||
elem = get_webelem(QRect(10, 10, 1, 1), self.frame)
|
||||
self.assertTrue(elem.is_visible(self.frame))
|
||||
assert elem.is_visible(self.frame)
|
||||
|
||||
|
||||
class IsVisibleCssTests(unittest.TestCase):
|
||||
class TestIsVisibleCss:
|
||||
|
||||
"""Tests for is_visible with CSS attributes.
|
||||
|
||||
@ -168,33 +169,34 @@ class IsVisibleCssTests(unittest.TestCase):
|
||||
frame: The FakeWebFrame we're using to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, stubs):
|
||||
self.frame = stubs.FakeWebFrame(QRect(0, 0, 100, 100))
|
||||
|
||||
def test_visibility_visible(self):
|
||||
"""Check that elements with "visibility = visible" are visible."""
|
||||
elem = get_webelem(QRect(0, 0, 10, 10), self.frame,
|
||||
visibility='visible')
|
||||
self.assertTrue(elem.is_visible(self.frame))
|
||||
assert elem.is_visible(self.frame)
|
||||
|
||||
def test_visibility_hidden(self):
|
||||
"""Check that elements with "visibility = hidden" are not visible."""
|
||||
elem = get_webelem(QRect(0, 0, 10, 10), self.frame,
|
||||
visibility='hidden')
|
||||
self.assertFalse(elem.is_visible(self.frame))
|
||||
assert not elem.is_visible(self.frame)
|
||||
|
||||
def test_display_inline(self):
|
||||
"""Check that elements with "display = inline" are visible."""
|
||||
elem = get_webelem(QRect(0, 0, 10, 10), self.frame, display='inline')
|
||||
self.assertTrue(elem.is_visible(self.frame))
|
||||
assert elem.is_visible(self.frame)
|
||||
|
||||
def test_display_none(self):
|
||||
"""Check that elements with "display = none" are not visible."""
|
||||
elem = get_webelem(QRect(0, 0, 10, 10), self.frame, display='none')
|
||||
self.assertFalse(elem.is_visible(self.frame))
|
||||
assert not elem.is_visible(self.frame)
|
||||
|
||||
|
||||
class IsVisibleIframeTests(unittest.TestCase):
|
||||
class TestIsVisibleIframe:
|
||||
|
||||
"""Tests for is_visible with a child frame.
|
||||
|
||||
@ -204,7 +206,8 @@ class IsVisibleIframeTests(unittest.TestCase):
|
||||
elem1-elem4: FakeWebElements to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, stubs):
|
||||
"""Set up the following base situation.
|
||||
|
||||
0, 0 300, 0
|
||||
@ -236,64 +239,64 @@ class IsVisibleIframeTests(unittest.TestCase):
|
||||
|
||||
def test_not_scrolled(self):
|
||||
"""Test base situation."""
|
||||
self.assertTrue(self.frame.geometry().contains(self.iframe.geometry()))
|
||||
self.assertTrue(self.elem1.is_visible(self.frame))
|
||||
self.assertTrue(self.elem2.is_visible(self.frame))
|
||||
self.assertFalse(self.elem3.is_visible(self.frame))
|
||||
self.assertTrue(self.elem4.is_visible(self.frame))
|
||||
assert self.frame.geometry().contains(self.iframe.geometry())
|
||||
assert self.elem1.is_visible(self.frame)
|
||||
assert self.elem2.is_visible(self.frame)
|
||||
assert not self.elem3.is_visible(self.frame)
|
||||
assert self.elem4.is_visible(self.frame)
|
||||
|
||||
def test_iframe_scrolled(self):
|
||||
"""Scroll iframe down so elem3 gets visible and elem1/elem2 not."""
|
||||
self.iframe.scrollPosition.return_value = QPoint(0, 100)
|
||||
self.assertFalse(self.elem1.is_visible(self.frame))
|
||||
self.assertFalse(self.elem2.is_visible(self.frame))
|
||||
self.assertTrue(self.elem3.is_visible(self.frame))
|
||||
self.assertTrue(self.elem4.is_visible(self.frame))
|
||||
assert not self.elem1.is_visible(self.frame)
|
||||
assert not self.elem2.is_visible(self.frame)
|
||||
assert self.elem3.is_visible(self.frame)
|
||||
assert self.elem4.is_visible(self.frame)
|
||||
|
||||
def test_mainframe_scrolled_iframe_visible(self):
|
||||
"""Scroll mainframe down so iframe is partly visible but elem1 not."""
|
||||
self.frame.scrollPosition.return_value = QPoint(0, 50)
|
||||
geom = self.frame.geometry().translated(self.frame.scrollPosition())
|
||||
self.assertFalse(geom.contains(self.iframe.geometry()))
|
||||
self.assertTrue(geom.intersects(self.iframe.geometry()))
|
||||
self.assertFalse(self.elem1.is_visible(self.frame))
|
||||
self.assertTrue(self.elem2.is_visible(self.frame))
|
||||
self.assertFalse(self.elem3.is_visible(self.frame))
|
||||
self.assertTrue(self.elem4.is_visible(self.frame))
|
||||
assert not geom.contains(self.iframe.geometry())
|
||||
assert geom.intersects(self.iframe.geometry())
|
||||
assert not self.elem1.is_visible(self.frame)
|
||||
assert self.elem2.is_visible(self.frame)
|
||||
assert not self.elem3.is_visible(self.frame)
|
||||
assert self.elem4.is_visible(self.frame)
|
||||
|
||||
def test_mainframe_scrolled_iframe_invisible(self):
|
||||
"""Scroll mainframe down so iframe is invisible."""
|
||||
self.frame.scrollPosition.return_value = QPoint(0, 110)
|
||||
geom = self.frame.geometry().translated(self.frame.scrollPosition())
|
||||
self.assertFalse(geom.contains(self.iframe.geometry()))
|
||||
self.assertFalse(geom.intersects(self.iframe.geometry()))
|
||||
self.assertFalse(self.elem1.is_visible(self.frame))
|
||||
self.assertFalse(self.elem2.is_visible(self.frame))
|
||||
self.assertFalse(self.elem3.is_visible(self.frame))
|
||||
self.assertTrue(self.elem4.is_visible(self.frame))
|
||||
assert not geom.contains(self.iframe.geometry())
|
||||
assert not geom.intersects(self.iframe.geometry())
|
||||
assert not self.elem1.is_visible(self.frame)
|
||||
assert not self.elem2.is_visible(self.frame)
|
||||
assert not self.elem3.is_visible(self.frame)
|
||||
assert self.elem4.is_visible(self.frame)
|
||||
|
||||
|
||||
class IsWritableTests(unittest.TestCase):
|
||||
class TestIsWritable:
|
||||
|
||||
"""Check is_writable."""
|
||||
|
||||
def test_writable(self):
|
||||
"""Test a normal element."""
|
||||
elem = get_webelem()
|
||||
self.assertTrue(elem.is_writable())
|
||||
assert elem.is_writable()
|
||||
|
||||
def test_disabled(self):
|
||||
"""Test a disabled element."""
|
||||
elem = get_webelem(attributes=['disabled'])
|
||||
self.assertFalse(elem.is_writable())
|
||||
assert not elem.is_writable()
|
||||
|
||||
def test_readonly(self):
|
||||
"""Test a readonly element."""
|
||||
elem = get_webelem(attributes=['readonly'])
|
||||
self.assertFalse(elem.is_writable())
|
||||
assert not elem.is_writable()
|
||||
|
||||
|
||||
class JavascriptEscapeTests(unittest.TestCase):
|
||||
class TestJavascriptEscape:
|
||||
|
||||
"""Check javascript_escape.
|
||||
|
||||
@ -301,33 +304,30 @@ class JavascriptEscapeTests(unittest.TestCase):
|
||||
STRINGS: A list of (input, output) tuples.
|
||||
"""
|
||||
|
||||
STRINGS = (
|
||||
@pytest.mark.parametrize('before, after', [
|
||||
('foo\\bar', r'foo\\bar'),
|
||||
('foo\nbar', r'foo\nbar'),
|
||||
("foo'bar", r"foo\'bar"),
|
||||
('foo"bar', r'foo\"bar'),
|
||||
)
|
||||
|
||||
def test_fake_escape(self):
|
||||
])
|
||||
def test_fake_escape(self, before, after):
|
||||
"""Test javascript escaping."""
|
||||
for before, after in self.STRINGS:
|
||||
with self.subTest(before=before):
|
||||
self.assertEqual(webelem.javascript_escape(before), after)
|
||||
assert webelem.javascript_escape(before) == after
|
||||
|
||||
|
||||
class GetChildFramesTests(unittest.TestCase):
|
||||
class TestGetChildFrames:
|
||||
|
||||
"""Check get_child_frames."""
|
||||
|
||||
def test_single_frame(self):
|
||||
def test_single_frame(self, stubs):
|
||||
"""Test get_child_frames with a single frame without children."""
|
||||
frame = stubs.FakeChildrenFrame()
|
||||
children = webelem.get_child_frames(frame)
|
||||
self.assertEqual(len(children), 1)
|
||||
self.assertIs(children[0], frame)
|
||||
assert len(children) == 1
|
||||
assert children[0] is frame
|
||||
frame.childFrames.assert_called_once_with()
|
||||
|
||||
def test_one_level(self):
|
||||
def test_one_level(self, stubs):
|
||||
r"""Test get_child_frames with one level of children.
|
||||
|
||||
o parent
|
||||
@ -338,15 +338,15 @@ class GetChildFramesTests(unittest.TestCase):
|
||||
child2 = stubs.FakeChildrenFrame()
|
||||
parent = stubs.FakeChildrenFrame([child1, child2])
|
||||
children = webelem.get_child_frames(parent)
|
||||
self.assertEqual(len(children), 3)
|
||||
self.assertIs(children[0], parent)
|
||||
self.assertIs(children[1], child1)
|
||||
self.assertIs(children[2], child2)
|
||||
assert len(children) == 3
|
||||
assert children[0] is parent
|
||||
assert children[1] is child1
|
||||
assert children[2] is child2
|
||||
parent.childFrames.assert_called_once_with()
|
||||
child1.childFrames.assert_called_once_with()
|
||||
child2.childFrames.assert_called_once_with()
|
||||
|
||||
def test_multiple_levels(self):
|
||||
def test_multiple_levels(self, stubs):
|
||||
r"""Test get_child_frames with multiple levels of children.
|
||||
|
||||
o root
|
||||
@ -360,189 +360,191 @@ class GetChildFramesTests(unittest.TestCase):
|
||||
stubs.FakeChildrenFrame(second[2:4])]
|
||||
root = stubs.FakeChildrenFrame(first)
|
||||
children = webelem.get_child_frames(root)
|
||||
self.assertEqual(len(children), 7)
|
||||
self.assertIs(children[0], root)
|
||||
assert len(children) == 7
|
||||
assert children[0] is root
|
||||
for frame in [root] + first + second:
|
||||
with self.subTest(frame=frame):
|
||||
frame.childFrames.assert_called_once_with()
|
||||
frame.childFrames.assert_called_once_with()
|
||||
|
||||
|
||||
class IsEditableTests(unittest.TestCase):
|
||||
class TestIsEditable:
|
||||
|
||||
"""Tests for is_editable."""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self):
|
||||
old_config = webelem.config
|
||||
webelem.config = None
|
||||
yield
|
||||
webelem.config = old_config
|
||||
|
||||
@pytest.fixture
|
||||
def stub_config(self, stubs, mocker):
|
||||
"""Fixture to create a config stub with an input section."""
|
||||
config = stubs.ConfigStub({'input': {}})
|
||||
mocker.patch('qutebrowser.browser.webelem.config', new=config)
|
||||
return config
|
||||
|
||||
def test_input_plain(self):
|
||||
"""Test with plain input element."""
|
||||
elem = get_webelem(tagname='input')
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_text(self):
|
||||
"""Test with text input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'text'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_text_caps(self):
|
||||
"""Test with text input element with caps attributes."""
|
||||
elem = get_webelem(tagname='INPUT', attributes={'TYPE': 'TEXT'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_email(self):
|
||||
"""Test with email input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'email'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_url(self):
|
||||
"""Test with url input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'url'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_tel(self):
|
||||
"""Test with tel input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'tel'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_number(self):
|
||||
"""Test with number input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'number'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_password(self):
|
||||
"""Test with password input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'password'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_search(self):
|
||||
"""Test with search input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'search'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_input_button(self):
|
||||
"""Button should not be editable."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'button'})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_input_checkbox(self):
|
||||
"""Checkbox should not be editable."""
|
||||
elem = get_webelem(tagname='input', attributes={'type': 'checkbox'})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_textarea(self):
|
||||
"""Test textarea element."""
|
||||
elem = get_webelem(tagname='textarea')
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_select(self):
|
||||
"""Test selectbox."""
|
||||
elem = get_webelem(tagname='select')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_input_disabled(self):
|
||||
"""Test disabled input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'disabled': None})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_input_readonly(self):
|
||||
"""Test readonly input element."""
|
||||
elem = get_webelem(tagname='input', attributes={'readonly': None})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_textarea_disabled(self):
|
||||
"""Test disabled textarea element."""
|
||||
elem = get_webelem(tagname='textarea', attributes={'disabled': None})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_textarea_readonly(self):
|
||||
"""Test readonly textarea element."""
|
||||
elem = get_webelem(tagname='textarea', attributes={'readonly': None})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': True}}))
|
||||
def test_embed_true(self):
|
||||
def test_embed_true(self, stub_config):
|
||||
"""Test embed-element with insert-mode-on-plugins true."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = True
|
||||
elem = get_webelem(tagname='embed')
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': True}}))
|
||||
def test_applet_true(self):
|
||||
def test_applet_true(self, stub_config):
|
||||
"""Test applet-element with insert-mode-on-plugins true."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = True
|
||||
elem = get_webelem(tagname='applet')
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': False}}))
|
||||
def test_embed_false(self):
|
||||
def test_embed_false(self, stub_config):
|
||||
"""Test embed-element with insert-mode-on-plugins false."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = False
|
||||
elem = get_webelem(tagname='embed')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': False}}))
|
||||
def test_applet_false(self):
|
||||
def test_applet_false(self, stub_config):
|
||||
"""Test applet-element with insert-mode-on-plugins false."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = False
|
||||
elem = get_webelem(tagname='applet')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_object_no_type(self):
|
||||
"""Test object-element without type."""
|
||||
elem = get_webelem(tagname='object')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_object_image(self):
|
||||
"""Test object-element with image type."""
|
||||
elem = get_webelem(tagname='object', attributes={'type': 'image/gif'})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': True}}))
|
||||
def test_object_application(self):
|
||||
def test_object_application(self, stub_config):
|
||||
"""Test object-element with application type."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = True
|
||||
elem = get_webelem(tagname='object',
|
||||
attributes={'type': 'application/foo'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': False}}))
|
||||
def test_object_application_false(self):
|
||||
def test_object_application_false(self, stub_config):
|
||||
"""Test object-element with application type but not ...-on-plugins."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = False
|
||||
elem = get_webelem(tagname='object',
|
||||
attributes={'type': 'application/foo'})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': True}}))
|
||||
def test_object_classid(self):
|
||||
def test_object_classid(self, stub_config):
|
||||
"""Test object-element with classid."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = True
|
||||
elem = get_webelem(tagname='object',
|
||||
attributes={'type': 'foo', 'classid': 'foo'})
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
@mock.patch('qutebrowser.browser.webelem.config', new=stubs.ConfigStub(
|
||||
{'input': {'insert-mode-on-plugins': False}}))
|
||||
def test_object_classid_false(self):
|
||||
def test_object_classid_false(self, stub_config):
|
||||
"""Test object-element with classid but not insert-mode-on-plugins."""
|
||||
stub_config.data['input']['insert-mode-on-plugins'] = False
|
||||
elem = get_webelem(tagname='object',
|
||||
attributes={'type': 'foo', 'classid': 'foo'})
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_div_empty(self):
|
||||
"""Test div-element without class."""
|
||||
elem = get_webelem(tagname='div')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_div_noneditable(self):
|
||||
"""Test div-element with non-editable class."""
|
||||
elem = get_webelem(tagname='div', classes='foo-kix-bar')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_div_xik(self):
|
||||
"""Test div-element with xik class."""
|
||||
elem = get_webelem(tagname='div', classes='foo kix-foo')
|
||||
self.assertTrue(elem.is_editable())
|
||||
assert elem.is_editable()
|
||||
|
||||
def test_div_xik_caps(self):
|
||||
"""Test div-element with xik class in caps.
|
||||
@ -550,13 +552,9 @@ class IsEditableTests(unittest.TestCase):
|
||||
This tests if classes are case sensitive as they should.
|
||||
"""
|
||||
elem = get_webelem(tagname='div', classes='KIX-FOO')
|
||||
self.assertFalse(elem.is_editable())
|
||||
assert not elem.is_editable()
|
||||
|
||||
def test_div_codemirror(self):
|
||||
"""Test div-element with codemirror class."""
|
||||
elem = get_webelem(tagname='div', classes='foo CodeMirror-foo')
|
||||
self.assertTrue(elem.is_editable())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert elem.is_editable()
|
@ -22,27 +22,25 @@
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import unittest
|
||||
import configparser
|
||||
import tempfile
|
||||
import types
|
||||
import shutil
|
||||
import argparse
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import QObject
|
||||
from PyQt5.QtGui import QColor
|
||||
import pytest
|
||||
|
||||
from qutebrowser.config import config, configexc
|
||||
from qutebrowser.test import helpers
|
||||
from qutebrowser.utils import objreg, standarddir
|
||||
|
||||
|
||||
class ConfigParserTests(unittest.TestCase):
|
||||
class TestConfigParser:
|
||||
|
||||
"""Test reading of ConfigParser."""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.cp = configparser.ConfigParser(interpolation=None,
|
||||
comment_prefixes='#')
|
||||
self.cp.optionxform = lambda opt: opt # be case-insensitive
|
||||
@ -52,43 +50,41 @@ class ConfigParserTests(unittest.TestCase):
|
||||
"""Test a simple option which is not transformed."""
|
||||
self.cp.read_dict({'general': {'ignore-case': 'false'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertFalse(self.cfg.get('general', 'ignore-case'))
|
||||
assert not self.cfg.get('general', 'ignore-case')
|
||||
|
||||
def test_transformed_section_old(self):
|
||||
"""Test a transformed section with the old name."""
|
||||
self.cp.read_dict({'permissions': {'allow-plugins': 'true'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertTrue(self.cfg.get('content', 'allow-plugins'))
|
||||
assert self.cfg.get('content', 'allow-plugins')
|
||||
|
||||
def test_transformed_section_new(self):
|
||||
"""Test a transformed section with the new name."""
|
||||
self.cp.read_dict({'content': {'allow-plugins': 'true'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertTrue(self.cfg.get('content', 'allow-plugins'))
|
||||
assert self.cfg.get('content', 'allow-plugins')
|
||||
|
||||
def test_transformed_option_old(self):
|
||||
"""Test a transformed option with the old name."""
|
||||
# WORKAROUND for unknown PyQt bug
|
||||
# Instance of 'str' has no 'name' member
|
||||
self.cp.read_dict({'colors': {'tab.fg.odd': 'pink'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertEqual(self.cfg.get('colors', 'tabs.fg.odd').name(),
|
||||
QColor('pink').name())
|
||||
actual = self.cfg.get('colors', 'tabs.fg.odd').name()
|
||||
expected = QColor('pink').name()
|
||||
assert actual == expected
|
||||
|
||||
def test_transformed_option_new(self):
|
||||
"""Test a transformed section with the new name."""
|
||||
# WORKAROUND for unknown PyQt bug
|
||||
# Instance of 'str' has no 'name' member
|
||||
self.cp.read_dict({'colors': {'tabs.fg.odd': 'pink'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertEqual(self.cfg.get('colors', 'tabs.fg.odd').name(),
|
||||
QColor('pink').name())
|
||||
actual = self.cfg.get('colors', 'tabs.fg.odd').name()
|
||||
expected = QColor('pink').name()
|
||||
assert actual == expected
|
||||
|
||||
def test_invalid_value(self):
|
||||
"""Test setting an invalid value."""
|
||||
self.cp.read_dict({'general': {'ignore-case': 'invalid'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
with self.assertRaises(configexc.ValidationError):
|
||||
with pytest.raises(configexc.ValidationError):
|
||||
self.cfg._validate_all()
|
||||
|
||||
def test_invalid_value_interpolated(self):
|
||||
@ -96,7 +92,7 @@ class ConfigParserTests(unittest.TestCase):
|
||||
self.cp.read_dict({'general': {'ignore-case': 'smart',
|
||||
'wrap-search': '${ignore-case}'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
with self.assertRaises(configexc.ValidationError):
|
||||
with pytest.raises(configexc.ValidationError):
|
||||
self.cfg._validate_all()
|
||||
|
||||
def test_interpolation(self):
|
||||
@ -104,8 +100,8 @@ class ConfigParserTests(unittest.TestCase):
|
||||
self.cp.read_dict({'general': {'ignore-case': 'false',
|
||||
'wrap-search': '${ignore-case}'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertFalse(self.cfg.get('general', 'ignore-case'))
|
||||
self.assertFalse(self.cfg.get('general', 'wrap-search'))
|
||||
assert not self.cfg.get('general', 'ignore-case')
|
||||
assert not self.cfg.get('general', 'wrap-search')
|
||||
|
||||
def test_interpolation_cross_section(self):
|
||||
"""Test setting an interpolated value from another section."""
|
||||
@ -116,50 +112,50 @@ class ConfigParserTests(unittest.TestCase):
|
||||
}
|
||||
)
|
||||
self.cfg._from_cp(self.cp)
|
||||
self.assertFalse(self.cfg.get('general', 'ignore-case'))
|
||||
self.assertFalse(self.cfg.get('network', 'do-not-track'))
|
||||
assert not self.cfg.get('general', 'ignore-case')
|
||||
assert not self.cfg.get('network', 'do-not-track')
|
||||
|
||||
def test_invalid_interpolation(self):
|
||||
"""Test an invalid interpolation."""
|
||||
self.cp.read_dict({'general': {'ignore-case': '${foo}'}})
|
||||
self.cfg._from_cp(self.cp)
|
||||
with self.assertRaises(configparser.InterpolationError):
|
||||
with pytest.raises(configparser.InterpolationError):
|
||||
self.cfg._validate_all()
|
||||
|
||||
def test_invalid_interpolation_syntax(self):
|
||||
"""Test an invalid interpolation syntax."""
|
||||
self.cp.read_dict({'general': {'ignore-case': '${'}})
|
||||
with self.assertRaises(configexc.InterpolationSyntaxError):
|
||||
with pytest.raises(configexc.InterpolationSyntaxError):
|
||||
self.cfg._from_cp(self.cp)
|
||||
|
||||
def test_invalid_section(self):
|
||||
"""Test an invalid section."""
|
||||
self.cp.read_dict({'foo': {'bar': 'baz'}})
|
||||
with self.assertRaises(configexc.NoSectionError):
|
||||
with pytest.raises(configexc.NoSectionError):
|
||||
self.cfg._from_cp(self.cp)
|
||||
|
||||
def test_invalid_option(self):
|
||||
"""Test an invalid option."""
|
||||
self.cp.read_dict({'general': {'bar': 'baz'}})
|
||||
with self.assertRaises(configexc.NoOptionError):
|
||||
with pytest.raises(configexc.NoOptionError):
|
||||
self.cfg._from_cp(self.cp)
|
||||
|
||||
def test_invalid_section_relaxed(self):
|
||||
"""Test an invalid section with relaxed=True."""
|
||||
self.cp.read_dict({'foo': {'bar': 'baz'}})
|
||||
self.cfg._from_cp(self.cp, relaxed=True)
|
||||
with self.assertRaises(configexc.NoSectionError):
|
||||
with pytest.raises(configexc.NoSectionError):
|
||||
self.cfg.get('foo', 'bar') # pylint: disable=bad-config-call
|
||||
|
||||
def test_invalid_option_relaxed(self):
|
||||
"""Test an invalid option with relaxed=True."""
|
||||
self.cp.read_dict({'general': {'bar': 'baz'}})
|
||||
self.cfg._from_cp(self.cp, relaxed=True)
|
||||
with self.assertRaises(configexc.NoOptionError):
|
||||
with pytest.raises(configexc.NoOptionError):
|
||||
self.cfg.get('general', 'bar') # pylint: disable=bad-config-call
|
||||
|
||||
|
||||
class DefaultConfigTests(unittest.TestCase):
|
||||
class TestDefaultConfig:
|
||||
|
||||
"""Test validating of the default config."""
|
||||
|
||||
@ -169,40 +165,32 @@ class DefaultConfigTests(unittest.TestCase):
|
||||
conf._validate_all()
|
||||
|
||||
|
||||
class ConfigInitTests(unittest.TestCase):
|
||||
class TestConfigInit:
|
||||
|
||||
"""Test initializing of the config."""
|
||||
|
||||
def setUp(self):
|
||||
self.temp_dir = tempfile.mkdtemp()
|
||||
self.conf_path = os.path.join(self.temp_dir, 'config')
|
||||
self.data_path = os.path.join(self.temp_dir, 'data')
|
||||
self.cache_path = os.path.join(self.temp_dir, 'cache')
|
||||
os.mkdir(self.conf_path)
|
||||
os.mkdir(self.data_path)
|
||||
os.mkdir(self.cache_path)
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self, tmpdir):
|
||||
self.conf_path = (tmpdir / 'config').ensure(dir=1)
|
||||
self.data_path = (tmpdir / 'data').ensure(dir=1)
|
||||
self.cache_path = (tmpdir / 'cache').ensure(dir=1)
|
||||
self.env = {
|
||||
'XDG_CONFIG_HOME': self.conf_path,
|
||||
'XDG_DATA_HOME': self.data_path,
|
||||
'XDG_CACHE_HOME': self.cache_path,
|
||||
'XDG_CONFIG_HOME': str(self.conf_path),
|
||||
'XDG_DATA_HOME': str(self.data_path),
|
||||
'XDG_CACHE_HOME': str(self.cache_path),
|
||||
}
|
||||
objreg.register('app', QObject())
|
||||
objreg.register('save-manager', mock.MagicMock())
|
||||
args = argparse.Namespace(relaxed_config=False)
|
||||
objreg.register('args', args)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.temp_dir)
|
||||
yield
|
||||
objreg.global_registry.clear()
|
||||
|
||||
def test_config_none(self):
|
||||
def test_config_none(self, monkeypatch):
|
||||
"""Test initializing with config path set to None."""
|
||||
args = types.SimpleNamespace(confdir='')
|
||||
with helpers.environ_set_temp(self.env):
|
||||
standarddir.init(args)
|
||||
config.init()
|
||||
self.assertFalse(os.listdir(self.conf_path))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
for k, v in self.env.items():
|
||||
monkeypatch.setenv(k, v)
|
||||
standarddir.init(args)
|
||||
config.init()
|
||||
assert not os.listdir(str(self.conf_path))
|
File diff suppressed because it is too large
Load Diff
78
tests/conftest.py
Normal file
78
tests/conftest.py
Normal file
@ -0,0 +1,78 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""The qutebrowser test suite contest file."""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def app_and_logging(qapp):
|
||||
"""Initialize a QApplication and logging.
|
||||
|
||||
This ensures that a QApplication is created and used by all tests.
|
||||
"""
|
||||
from log import init
|
||||
init()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def stubs():
|
||||
"""Provide access to stub objects useful for testing."""
|
||||
import stubs
|
||||
return stubs
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def unicode_encode_err():
|
||||
"""Provide a fake UnicodeEncodeError exception."""
|
||||
return UnicodeEncodeError('ascii', # codec
|
||||
'', # object
|
||||
0, # start
|
||||
2, # end
|
||||
'fake exception') # reason
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def webpage():
|
||||
"""Get a new QWebPage object."""
|
||||
from PyQt5.QtWebKitWidgets import QWebPage
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager
|
||||
|
||||
page = QWebPage()
|
||||
nam = page.networkAccessManager()
|
||||
nam.setNetworkAccessible(QNetworkAccessManager.NotAccessible)
|
||||
return page
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_keyevent_factory():
|
||||
"""Fixture that when called will return a mock instance of a QKeyEvent."""
|
||||
from unittest import mock
|
||||
from PyQt5.QtGui import QKeyEvent
|
||||
|
||||
def fake_keyevent(key, modifiers=0, text=''):
|
||||
"""Generate a new fake QKeyPressEvent."""
|
||||
evtmock = mock.create_autospec(QKeyEvent, instance=True)
|
||||
evtmock.key.return_value = key
|
||||
evtmock.modifiers.return_value = modifiers
|
||||
evtmock.text.return_value = text
|
||||
return evtmock
|
||||
|
||||
return fake_keyevent
|
289
tests/keyinput/test_basekeyparser.py
Normal file
289
tests/keyinput/test_basekeyparser.py
Normal file
@ -0,0 +1,289 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
"""Tests for BaseKeyParser."""
|
||||
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
import pytest
|
||||
|
||||
from qutebrowser.keyinput import basekeyparser
|
||||
from qutebrowser.utils import objreg, log
|
||||
|
||||
|
||||
CONFIG = {'input': {'timeout': 100}}
|
||||
|
||||
|
||||
BINDINGS = {'test': {'<Ctrl-a>': 'ctrla',
|
||||
'a': 'a',
|
||||
'ba': 'ba',
|
||||
'ax': 'ax',
|
||||
'ccc': 'ccc'},
|
||||
'test2': {'foo': 'bar', '<Ctrl+X>': 'ctrlx'}}
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
def fake_keyconfig():
|
||||
"""Create a mock of a KeyConfiguration and register it into objreg."""
|
||||
fake_keyconfig = mock.Mock(spec=['get_bindings_for'])
|
||||
fake_keyconfig.get_bindings_for.side_effect = lambda s: BINDINGS[s]
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
yield
|
||||
objreg.delete('key-config')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_timer(mocker, stubs):
|
||||
"""Mock the Timer class used by the usertypes module with a stub."""
|
||||
mocker.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
|
||||
|
||||
class TestSplitCount:
|
||||
|
||||
"""Test the _split_count method.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser we're testing.
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_count=True)
|
||||
|
||||
def test_onlycount(self):
|
||||
"""Test split_count with only a count."""
|
||||
self.kp._keystring = '10'
|
||||
assert self.kp._split_count() == (10, '')
|
||||
|
||||
def test_normalcount(self):
|
||||
"""Test split_count with count and text."""
|
||||
self.kp._keystring = '10foo'
|
||||
assert self.kp._split_count() == (10, 'foo')
|
||||
|
||||
def test_minuscount(self):
|
||||
"""Test split_count with a negative count."""
|
||||
self.kp._keystring = '-1foo'
|
||||
assert self.kp._split_count() == (None, '-1foo')
|
||||
|
||||
def test_expcount(self):
|
||||
"""Test split_count with an exponential count."""
|
||||
self.kp._keystring = '10e4foo'
|
||||
assert self.kp._split_count() == (10, 'e4foo')
|
||||
|
||||
def test_nocount(self):
|
||||
"""Test split_count with only a command."""
|
||||
self.kp._keystring = 'foo'
|
||||
assert self.kp._split_count() == (None, 'foo')
|
||||
|
||||
def test_nosupport(self):
|
||||
"""Test split_count with a count when counts aren't supported."""
|
||||
self.kp._supports_count = False
|
||||
self.kp._keystring = '10foo'
|
||||
assert self.kp._split_count() == (None, '10foo')
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('fake_keyconfig', 'mock_timer')
|
||||
class TestReadConfig:
|
||||
|
||||
"""Test reading the config."""
|
||||
|
||||
def test_read_config_invalid(self):
|
||||
"""Test reading config without setting it before."""
|
||||
kp = basekeyparser.BaseKeyParser(0)
|
||||
with pytest.raises(ValueError):
|
||||
kp.read_config()
|
||||
|
||||
def test_read_config_valid(self):
|
||||
"""Test reading config."""
|
||||
kp = basekeyparser.BaseKeyParser(0, supports_count=True,
|
||||
supports_chains=True)
|
||||
kp.read_config('test')
|
||||
assert 'ccc' in kp.bindings
|
||||
assert 'ctrl+a' in kp.special_bindings
|
||||
kp.read_config('test2')
|
||||
assert 'ccc' not in kp.bindings
|
||||
assert 'ctrl+a' not in kp.special_bindings
|
||||
assert 'foo' in kp.bindings
|
||||
assert 'ctrl+x' in kp.special_bindings
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_timer')
|
||||
class TestSpecialKeys:
|
||||
|
||||
"""Check execute() with special keys.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser to be tested.
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, caplog, fake_keyconfig):
|
||||
self.kp = basekeyparser.BaseKeyParser(0)
|
||||
self.kp.execute = mock.Mock()
|
||||
with caplog.atLevel(logging.WARNING, log.keyboard.name):
|
||||
# Ignoring keychain 'ccc' in mode 'test' because keychains are not
|
||||
# supported there.
|
||||
self.kp.read_config('test')
|
||||
|
||||
def test_valid_key(self, fake_keyevent_factory):
|
||||
"""Test a valid special keyevent."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, Qt.ControlModifier))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_X, Qt.ControlModifier))
|
||||
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
|
||||
|
||||
def test_invalid_key(self, fake_keyevent_factory):
|
||||
"""Test an invalid special keyevent."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, (Qt.ControlModifier |
|
||||
Qt.AltModifier)))
|
||||
assert not self.kp.execute.called
|
||||
|
||||
def test_keychain(self, fake_keyevent_factory):
|
||||
"""Test a keychain."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A))
|
||||
assert not self.kp.execute.called
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_timer')
|
||||
class TestKeyChain:
|
||||
|
||||
"""Test execute() with keychain support.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser to be tested.
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, fake_keyconfig):
|
||||
"""Set up mocks and read the test config."""
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
|
||||
supports_count=False)
|
||||
self.kp.execute = mock.Mock()
|
||||
self.kp.read_config('test')
|
||||
|
||||
def test_valid_special_key(self, fake_keyevent_factory):
|
||||
"""Test valid special key."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, Qt.ControlModifier))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_X, Qt.ControlModifier))
|
||||
self.kp.execute.assert_called_once_with('ctrla', self.kp.Type.special)
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_invalid_special_key(self, fake_keyevent_factory):
|
||||
"""Test invalid special key."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, (Qt.ControlModifier |
|
||||
Qt.AltModifier)))
|
||||
assert not self.kp.execute.called
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_keychain(self, fake_keyevent_factory):
|
||||
"""Test valid keychain."""
|
||||
# Press 'x' which is ignored because of no match
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_X, text='x'))
|
||||
# Then start the real chain
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_ambiguous_keychain(self, fake_keyevent_factory, mocker, stubs):
|
||||
"""Test ambiguous keychain."""
|
||||
mocker.patch('qutebrowser.keyinput.basekeyparser.config',
|
||||
new=stubs.ConfigStub(CONFIG))
|
||||
timer = self.kp._ambiguous_timer
|
||||
assert not timer.isActive()
|
||||
# We start with 'a' where the keychain gives us an ambiguous result.
|
||||
# Then we check if the timer has been set up correctly
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
assert not self.kp.execute.called
|
||||
assert timer.isSingleShot()
|
||||
assert timer.interval() == 100
|
||||
assert timer.isActive()
|
||||
# Now we type an 'x' and check 'ax' has been executed and the timer
|
||||
# stopped.
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_X, text='x'))
|
||||
self.kp.execute.assert_called_once_with('ax', self.kp.Type.chain, None)
|
||||
assert not timer.isActive()
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_invalid_keychain(self, fake_keyevent_factory):
|
||||
"""Test invalid keychain."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_C, text='c'))
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('mock_timer')
|
||||
class TestCount:
|
||||
|
||||
"""Test execute() with counts."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, fake_keyconfig):
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
|
||||
supports_count=True)
|
||||
self.kp.execute = mock.Mock()
|
||||
self.kp.read_config('test')
|
||||
|
||||
def test_no_count(self, fake_keyevent_factory):
|
||||
"""Test with no count added."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_count_0(self, fake_keyevent_factory):
|
||||
"""Test with count=0."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_0, text='0'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 0)
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_count_42(self, fake_keyevent_factory):
|
||||
"""Test with count=42."""
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_4, text='4'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_2, text='2'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, 42)
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_count_42_invalid(self, fake_keyevent_factory):
|
||||
"""Test with count=42 and invalid command."""
|
||||
# Invalid call with ccx gets ignored
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_4, text='4'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_2, text='2'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='c'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='c'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='x'))
|
||||
assert not self.kp.execute.called
|
||||
assert self.kp._keystring == ''
|
||||
# Valid call with ccc gets the correct count
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_4, text='2'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_2, text='3'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='c'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='c'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='c'))
|
||||
self.kp.execute.assert_called_once_with('ccc', self.kp.Type.chain, 23)
|
||||
assert self.kp._keystring == ''
|
@ -21,11 +21,10 @@
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
import pytest
|
||||
|
||||
from qutebrowser.keyinput import modeparsers
|
||||
from qutebrowser.test import stubs, helpers
|
||||
from qutebrowser.utils import objreg
|
||||
|
||||
|
||||
@ -39,11 +38,7 @@ fake_keyconfig = mock.Mock(spec=['get_bindings_for'])
|
||||
fake_keyconfig.get_bindings_for.side_effect = lambda s: BINDINGS[s]
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
@mock.patch('qutebrowser.keyinput.modeparsers.config',
|
||||
new=stubs.ConfigStub(CONFIG))
|
||||
class NormalKeyParserTests(unittest.TestCase):
|
||||
class TestsNormalKeyParser:
|
||||
|
||||
"""Tests for NormalKeyParser.
|
||||
|
||||
@ -53,46 +48,47 @@ class NormalKeyParserTests(unittest.TestCase):
|
||||
|
||||
# pylint: disable=protected-access
|
||||
|
||||
def setUp(self):
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self, mocker, stubs):
|
||||
"""Set up mocks and read the test config."""
|
||||
mocker.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
|
||||
new=stubs.FakeTimer)
|
||||
mocker.patch('qutebrowser.keyinput.modeparsers.config',
|
||||
new=stubs.ConfigStub(CONFIG))
|
||||
|
||||
objreg.register('key-config', fake_keyconfig)
|
||||
self.kp = modeparsers.NormalKeyParser(0)
|
||||
self.kp.execute = mock.Mock()
|
||||
|
||||
def tearDown(self):
|
||||
yield
|
||||
objreg.delete('key-config')
|
||||
|
||||
def test_keychain(self):
|
||||
def test_keychain(self, fake_keyevent_factory):
|
||||
"""Test valid keychain."""
|
||||
# Press 'x' which is ignored because of no match
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_X, text='x'))
|
||||
# Then start the real chain
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_A, text='a'))
|
||||
self.kp.execute.assert_called_once_with('ba', self.kp.Type.chain, None)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
assert self.kp._keystring == ''
|
||||
|
||||
def test_partial_keychain_timeout(self):
|
||||
def test_partial_keychain_timeout(self, fake_keyevent_factory):
|
||||
"""Test partial keychain timeout."""
|
||||
timer = self.kp._partial_timer
|
||||
self.assertFalse(timer.isActive())
|
||||
assert not timer.isActive()
|
||||
# Press 'b' for a partial match.
|
||||
# Then we check if the timer has been set up correctly
|
||||
self.kp.handle(helpers.fake_keyevent(Qt.Key_B, text='b'))
|
||||
self.assertTrue(timer.isSingleShot())
|
||||
self.assertEqual(timer.interval(), 100)
|
||||
self.assertTrue(timer.isActive())
|
||||
self.kp.handle(fake_keyevent_factory(Qt.Key_B, text='b'))
|
||||
assert timer.isSingleShot()
|
||||
assert timer.interval() == 100
|
||||
assert timer.isActive()
|
||||
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
self.assertEqual(self.kp._keystring, 'b')
|
||||
assert not self.kp.execute.called
|
||||
assert self.kp._keystring == 'b'
|
||||
# Now simulate a timeout and check the keystring has been cleared.
|
||||
keystring_updated_mock = mock.Mock()
|
||||
self.kp.keystring_updated.connect(keystring_updated_mock)
|
||||
timer.timeout.emit()
|
||||
self.assertFalse(self.kp.execute.called)
|
||||
self.assertEqual(self.kp._keystring, '')
|
||||
assert not self.kp.execute.called
|
||||
assert self.kp._keystring == ''
|
||||
keystring_updated_mock.assert_called_once_with('')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
52
tests/mainwindow/conftest.py
Normal file
52
tests/mainwindow/conftest.py
Normal file
@ -0,0 +1,52 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""pytest fixtures and utilities for testing.
|
||||
|
||||
Fixtures defined here will be visible to all test files in this directory and
|
||||
below.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.config.config import ConfigManager
|
||||
from qutebrowser.utils import objreg
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
def default_config():
|
||||
"""
|
||||
Fixture that registers an empty config object into the objreg module.
|
||||
|
||||
Should be used by tests which create widgets that obtain their initial
|
||||
state from the global config object.
|
||||
|
||||
Note:
|
||||
|
||||
If we declare this fixture like this:
|
||||
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
|
||||
Then all tests below this file will have a default config registered
|
||||
and ready for use. Is that desirable?
|
||||
"""
|
||||
config_obj = ConfigManager(configdir=None, fname=None, relaxed=True)
|
||||
objreg.register('config', config_obj)
|
||||
yield config_obj
|
||||
objreg.delete('config')
|
@ -17,19 +17,32 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""The qutebrowser test suite."""
|
||||
|
||||
import atexit
|
||||
"""Test Percentage widget."""
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
import pytest
|
||||
|
||||
from qutebrowser.test import log
|
||||
from qutebrowser.mainwindow.statusbar.percentage import Percentage
|
||||
|
||||
# We create a singleton QApplication here.
|
||||
|
||||
qApp = QApplication([])
|
||||
qApp.setApplicationName('qutebrowser')
|
||||
qApp.processEvents()
|
||||
atexit.register(qApp.processEvents)
|
||||
atexit.register(qApp.quit)
|
||||
log.init()
|
||||
@pytest.mark.parametrize('y, expected', [
|
||||
(0, '[top]'),
|
||||
(100, '[bot]'),
|
||||
(75, '[75%]'),
|
||||
(25, '[25%]'),
|
||||
(5, '[ 5%]'),
|
||||
])
|
||||
def test_percentage_text(qtbot, y, expected):
|
||||
"""
|
||||
Test text displayed by the widget based on the y position of a page.
|
||||
|
||||
Args:
|
||||
qtbot: pytestqt.plugin.QtBot fixture
|
||||
y: y position of the page as an int in the range [0, 100].
|
||||
parametrized.
|
||||
expected: expected text given y position. parametrized.
|
||||
"""
|
||||
percentage = Percentage()
|
||||
qtbot.add_widget(percentage)
|
||||
percentage.set_perc(None, y=y)
|
||||
assert percentage.text() == expected
|
74
tests/mainwindow/statusbar/test_progress.py
Normal file
74
tests/mainwindow/statusbar/test_progress.py
Normal file
@ -0,0 +1,74 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Test Progress widget."""
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.browser import webview
|
||||
from qutebrowser.mainwindow.statusbar.progress import Progress
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def progress_widget(qtbot, default_config):
|
||||
"""Create a Progress widget and checks its initial state."""
|
||||
widget = Progress()
|
||||
qtbot.add_widget(widget)
|
||||
assert not widget.isVisible()
|
||||
assert not widget.isTextVisible()
|
||||
return widget
|
||||
|
||||
|
||||
def test_load_started(progress_widget):
|
||||
"""Ensure the Progress widget reacts properly when the page starts loading.
|
||||
|
||||
Args:
|
||||
progress_widget: Progress widget that will be tested.
|
||||
"""
|
||||
progress_widget.on_load_started()
|
||||
assert progress_widget.value() == 0
|
||||
assert progress_widget.isVisible()
|
||||
|
||||
|
||||
# mock tab object
|
||||
Tab = namedtuple('Tab', 'progress load_status')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('tab, expected_visible', [
|
||||
(Tab(15, webview.LoadStatus.loading), True),
|
||||
(Tab(100, webview.LoadStatus.success), False),
|
||||
(Tab(100, webview.LoadStatus.error), False),
|
||||
(Tab(100, webview.LoadStatus.warn), False),
|
||||
(Tab(100, webview.LoadStatus.none), False),
|
||||
])
|
||||
def test_tab_changed(progress_widget, tab, expected_visible):
|
||||
"""Test that progress widget value and visibility state match expectations.
|
||||
|
||||
This uses a dummy Tab object.
|
||||
|
||||
Args:
|
||||
progress_widget: Progress widget that will be tested.
|
||||
"""
|
||||
progress_widget.on_tab_changed(tab)
|
||||
actual = progress_widget.value(), progress_widget.isVisible()
|
||||
expected = tab.progress, expected_visible
|
||||
assert actual == expected
|
@ -17,4 +17,27 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Tests for the qutebrowser.utils package."""
|
||||
|
||||
"""Test TextBase widget."""
|
||||
|
||||
from qutebrowser.mainwindow.statusbar.textbase import TextBase
|
||||
|
||||
|
||||
def test_elided_text(qtbot):
|
||||
"""Ensure that a widget too small to hold the entire label text will elide.
|
||||
|
||||
Note:
|
||||
It is difficult to check what is actually being drawn in a portable
|
||||
way, so at least we ensure our customized methods are being called and
|
||||
the elided string contains the horizontal ellipsis character.
|
||||
|
||||
Args:
|
||||
qtbot: pytestqt.plugin.QtBot fixture
|
||||
"""
|
||||
label = TextBase()
|
||||
qtbot.add_widget(label)
|
||||
long_string = 'Hello world! ' * 20
|
||||
label.setText(long_string)
|
||||
label.resize(100, 50)
|
||||
label.show()
|
||||
assert '…' in label._elided_text # pylint: disable=protected-access
|
@ -23,19 +23,16 @@
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import unittest
|
||||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import QProcess
|
||||
import pytest
|
||||
|
||||
from qutebrowser.misc import editor
|
||||
from qutebrowser.test import stubs, helpers
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
class ArgTests(unittest.TestCase):
|
||||
class TestArg:
|
||||
|
||||
"""Test argument handling.
|
||||
|
||||
@ -43,52 +40,48 @@ class ArgTests(unittest.TestCase):
|
||||
editor: The ExternalEditor instance to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self, mocker, stubs):
|
||||
mocker.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
self.config = stubs.ConfigStub()
|
||||
mocker.patch('qutebrowser.misc.editor.config', new=self.config)
|
||||
self.editor = editor.ExternalEditor(0)
|
||||
yield
|
||||
self.editor._cleanup() # pylint: disable=protected-access
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}))
|
||||
def test_simple_start_args(self, _proc_mock):
|
||||
def test_simple_start_args(self):
|
||||
"""Test starting editor without arguments."""
|
||||
self.config.data = {
|
||||
'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}
|
||||
self.editor.edit("")
|
||||
self.editor._proc.start.assert_called_with("bin", [])
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': ['bin', 'foo', 'bar'],
|
||||
'editor-encoding': 'utf-8'}}))
|
||||
def test_start_args(self, _proc_mock):
|
||||
def test_start_args(self):
|
||||
"""Test starting editor with static arguments."""
|
||||
self.config.data = {'general': {'editor': ['bin', 'foo', 'bar'],
|
||||
'editor-encoding': 'utf-8'}}
|
||||
self.editor.edit("")
|
||||
self.editor._proc.start.assert_called_with("bin", ["foo", "bar"])
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': ['bin', 'foo', '{}', 'bar'],
|
||||
'editor-encoding': 'utf-8'}}))
|
||||
def test_placeholder(self, _proc_mock):
|
||||
def test_placeholder(self):
|
||||
"""Test starting editor with placeholder argument."""
|
||||
self.config.data = {'general': {'editor': ['bin', 'foo', '{}', 'bar'],
|
||||
'editor-encoding': 'utf-8'}}
|
||||
self.editor.edit("")
|
||||
filename = self.editor._filename
|
||||
self.editor._proc.start.assert_called_with(
|
||||
"bin", ["foo", filename, "bar"])
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': ['bin', 'foo{}bar'],
|
||||
'editor-encoding': 'utf-8'}}))
|
||||
def test_in_arg_placeholder(self, _proc_mock):
|
||||
def test_in_arg_placeholder(self):
|
||||
"""Test starting editor with placeholder argument inside argument."""
|
||||
self.config.data = {'general': {'editor': ['bin', 'foo{}bar'],
|
||||
'editor-encoding': 'utf-8'}}
|
||||
self.editor.edit("")
|
||||
self.editor._proc.start.assert_called_with("bin", ["foo{}bar"])
|
||||
|
||||
def tearDown(self):
|
||||
self.editor._cleanup() # pylint: disable=protected-access
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.message', new=helpers.MessageModule())
|
||||
@mock.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}))
|
||||
class FileHandlingTests(unittest.TestCase):
|
||||
class TestFileHandling:
|
||||
|
||||
"""Test creation/deletion of tempfile.
|
||||
|
||||
@ -96,42 +89,49 @@ class FileHandlingTests(unittest.TestCase):
|
||||
editor: The ExternalEditor instance to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, mocker, stubs):
|
||||
mocker.patch('qutebrowser.misc.editor.message',
|
||||
new=stubs.MessageModule())
|
||||
mocker.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
mocker.patch('qutebrowser.misc.editor.config',
|
||||
new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''],
|
||||
'editor-encoding': 'utf-8'}}))
|
||||
self.editor = editor.ExternalEditor(0)
|
||||
|
||||
def test_file_handling_closed_ok(self, _proc_mock):
|
||||
def test_file_handling_closed_ok(self):
|
||||
"""Test file handling when closing with an exit status == 0."""
|
||||
self.editor.edit("")
|
||||
filename = self.editor._filename
|
||||
self.assertTrue(os.path.exists(filename))
|
||||
assert os.path.exists(filename)
|
||||
self.editor.on_proc_closed(0, QProcess.NormalExit)
|
||||
self.assertFalse(os.path.exists(filename))
|
||||
assert not os.path.exists(filename)
|
||||
|
||||
def test_file_handling_closed_error(self, _proc_mock):
|
||||
def test_file_handling_closed_error(self, caplog):
|
||||
"""Test file handling when closing with an exit status != 0."""
|
||||
self.editor.edit("")
|
||||
filename = self.editor._filename
|
||||
self.assertTrue(os.path.exists(filename))
|
||||
with self.assertLogs('message', logging.ERROR):
|
||||
assert os.path.exists(filename)
|
||||
with caplog.atLevel(logging.ERROR):
|
||||
self.editor.on_proc_closed(1, QProcess.NormalExit)
|
||||
self.assertFalse(os.path.exists(filename))
|
||||
assert len(caplog.records()) == 2
|
||||
assert not os.path.exists(filename)
|
||||
|
||||
def test_file_handling_closed_crash(self, _proc_mock):
|
||||
def test_file_handling_closed_crash(self, caplog):
|
||||
"""Test file handling when closing with a crash."""
|
||||
self.editor.edit("")
|
||||
filename = self.editor._filename
|
||||
self.assertTrue(os.path.exists(filename))
|
||||
with self.assertLogs('message', logging.ERROR):
|
||||
assert os.path.exists(filename)
|
||||
with caplog.atLevel(logging.ERROR):
|
||||
self.editor.on_proc_error(QProcess.Crashed)
|
||||
assert len(caplog.records()) == 2
|
||||
self.editor.on_proc_closed(0, QProcess.CrashExit)
|
||||
self.assertFalse(os.path.exists(filename))
|
||||
assert not os.path.exists(filename)
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}))
|
||||
class TextModifyTests(unittest.TestCase):
|
||||
class TestModifyTests:
|
||||
|
||||
"""Tests to test if the text gets saved/loaded correctly.
|
||||
|
||||
@ -139,7 +139,12 @@ class TextModifyTests(unittest.TestCase):
|
||||
editor: The ExternalEditor instance to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, mocker, stubs):
|
||||
mocker.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
mocker.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}))
|
||||
self.editor = editor.ExternalEditor(0)
|
||||
self.editor.editing_finished = mock.Mock()
|
||||
|
||||
@ -164,45 +169,40 @@ class TextModifyTests(unittest.TestCase):
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
def test_empty_input(self, _proc_mock):
|
||||
def test_empty_input(self):
|
||||
"""Test if an empty input gets modified correctly."""
|
||||
self.editor.edit("")
|
||||
self.assertEqual(self._read(), "")
|
||||
assert self._read() == ""
|
||||
self._write("Hello")
|
||||
self.editor.on_proc_closed(0, QProcess.NormalExit)
|
||||
self.editor.editing_finished.emit.assert_called_with("Hello")
|
||||
|
||||
def test_simple_input(self, _proc_mock):
|
||||
def test_simple_input(self):
|
||||
"""Test if an empty input gets modified correctly."""
|
||||
self.editor.edit("Hello")
|
||||
self.assertEqual(self._read(), "Hello")
|
||||
assert self._read() == "Hello"
|
||||
self._write("World")
|
||||
self.editor.on_proc_closed(0, QProcess.NormalExit)
|
||||
self.editor.editing_finished.emit.assert_called_with("World")
|
||||
|
||||
def test_umlaut(self, _proc_mock):
|
||||
def test_umlaut(self):
|
||||
"""Test if umlauts works correctly."""
|
||||
self.editor.edit("Hällö Wörld")
|
||||
self.assertEqual(self._read(), "Hällö Wörld")
|
||||
assert self._read() == "Hällö Wörld"
|
||||
self._write("Überprüfung")
|
||||
self.editor.on_proc_closed(0, QProcess.NormalExit)
|
||||
self.editor.editing_finished.emit.assert_called_with("Überprüfung")
|
||||
|
||||
def test_unicode(self, _proc_mock):
|
||||
def test_unicode(self):
|
||||
"""Test if other UTF8 chars work correctly."""
|
||||
self.editor.edit("\u2603") # Unicode snowman
|
||||
self.assertEqual(self._read(), "\u2603")
|
||||
assert self._read() == "\u2603"
|
||||
self._write("\u2601") # Cloud
|
||||
self.editor.on_proc_closed(0, QProcess.NormalExit)
|
||||
self.editor.editing_finished.emit.assert_called_with("\u2601")
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
@mock.patch('qutebrowser.misc.editor.message', new=helpers.MessageModule())
|
||||
@mock.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}))
|
||||
class ErrorMessageTests(unittest.TestCase):
|
||||
class TestErrorMessage:
|
||||
|
||||
"""Test if statusbar error messages get emitted correctly.
|
||||
|
||||
@ -210,21 +210,28 @@ class ErrorMessageTests(unittest.TestCase):
|
||||
editor: The ExternalEditor instance to test.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self, mocker, stubs):
|
||||
mocker.patch('qutebrowser.misc.editor.QProcess',
|
||||
new_callable=stubs.FakeQProcess)
|
||||
mocker.patch('qutebrowser.misc.editor.message',
|
||||
new=stubs.MessageModule())
|
||||
mocker.patch('qutebrowser.misc.editor.config', new=stubs.ConfigStub(
|
||||
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}))
|
||||
self.editor = editor.ExternalEditor(0)
|
||||
yield
|
||||
self.editor._cleanup() # pylint: disable=protected-access
|
||||
|
||||
def test_proc_error(self, _proc_mock):
|
||||
def test_proc_error(self, caplog):
|
||||
"""Test on_proc_error."""
|
||||
self.editor.edit("")
|
||||
with self.assertLogs('message', logging.ERROR):
|
||||
with caplog.atLevel(logging.ERROR, 'message'):
|
||||
self.editor.on_proc_error(QProcess.Crashed)
|
||||
assert len(caplog.records()) == 2
|
||||
|
||||
def test_proc_return(self, _proc_mock):
|
||||
def test_proc_return(self, caplog):
|
||||
"""Test on_proc_finished with a bad exit status."""
|
||||
self.editor.edit("")
|
||||
with self.assertLogs('message', logging.ERROR):
|
||||
with caplog.atLevel(logging.ERROR, 'message'):
|
||||
self.editor.on_proc_closed(1, QProcess.NormalExit)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert len(caplog.records()) == 3
|
@ -22,40 +22,40 @@
|
||||
# pylint: disable=protected-access
|
||||
|
||||
import inspect
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtWidgets import QLineEdit
|
||||
import pytest
|
||||
|
||||
from qutebrowser.misc import readline
|
||||
from qutebrowser.test import stubs
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.readline.QApplication',
|
||||
new_callable=stubs.FakeQApplication)
|
||||
class NoneWidgetTests(unittest.TestCase):
|
||||
@pytest.fixture
|
||||
def mocked_qapp(mocker, stubs):
|
||||
"""Fixture that mocks readline.QApplication and returns it."""
|
||||
return mocker.patch('qutebrowser.misc.readline.QApplication',
|
||||
new_callable=stubs.FakeQApplication)
|
||||
|
||||
"""Tests when the focused widget is None."""
|
||||
|
||||
def setUp(self):
|
||||
class TestNoneWidget:
|
||||
|
||||
"""Test if there are no exceptions when the widget is None."""
|
||||
|
||||
def test_none(self, mocked_qapp):
|
||||
"""Call each rl_* method with a None focusWidget."""
|
||||
self.bridge = readline.ReadlineBridge()
|
||||
|
||||
def test_none(self, qapp):
|
||||
"""Test if there are no exceptions when the widget is None."""
|
||||
qapp.focusWidget = mock.Mock(return_value=None)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=None)
|
||||
for name, method in inspect.getmembers(self.bridge, inspect.ismethod):
|
||||
with self.subTest(name=name):
|
||||
if name.startswith('rl_'):
|
||||
method()
|
||||
if name.startswith('rl_'):
|
||||
method()
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.misc.readline.QApplication',
|
||||
new_callable=stubs.FakeQApplication)
|
||||
class ReadlineBridgeTest(unittest.TestCase):
|
||||
class TestReadlineBridgeTest:
|
||||
|
||||
"""Tests for readline bridge."""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.qle = mock.Mock()
|
||||
self.qle.__class__ = QLineEdit
|
||||
self.bridge = readline.ReadlineBridge()
|
||||
@ -64,104 +64,100 @@ class ReadlineBridgeTest(unittest.TestCase):
|
||||
"""Set the value the fake QLineEdit should return for selectedText."""
|
||||
self.qle.configure_mock(**{'selectedText.return_value': text})
|
||||
|
||||
def test_rl_backward_char(self, qapp):
|
||||
def test_rl_backward_char(self, mocked_qapp):
|
||||
"""Test rl_backward_char."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_backward_char()
|
||||
self.qle.cursorBackward.assert_called_with(False)
|
||||
|
||||
def test_rl_forward_char(self, qapp):
|
||||
def test_rl_forward_char(self, mocked_qapp):
|
||||
"""Test rl_forward_char."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_forward_char()
|
||||
self.qle.cursorForward.assert_called_with(False)
|
||||
|
||||
def test_rl_backward_word(self, qapp):
|
||||
def test_rl_backward_word(self, mocked_qapp):
|
||||
"""Test rl_backward_word."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_backward_word()
|
||||
self.qle.cursorWordBackward.assert_called_with(False)
|
||||
|
||||
def test_rl_forward_word(self, qapp):
|
||||
def test_rl_forward_word(self, mocked_qapp):
|
||||
"""Test rl_forward_word."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_forward_word()
|
||||
self.qle.cursorWordForward.assert_called_with(False)
|
||||
|
||||
def test_rl_beginning_of_line(self, qapp):
|
||||
def test_rl_beginning_of_line(self, mocked_qapp):
|
||||
"""Test rl_beginning_of_line."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_beginning_of_line()
|
||||
self.qle.home.assert_called_with(False)
|
||||
|
||||
def test_rl_end_of_line(self, qapp):
|
||||
def test_rl_end_of_line(self, mocked_qapp):
|
||||
"""Test rl_end_of_line."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_end_of_line()
|
||||
self.qle.end.assert_called_with(False)
|
||||
|
||||
def test_rl_delete_char(self, qapp):
|
||||
def test_rl_delete_char(self, mocked_qapp):
|
||||
"""Test rl_delete_char."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_delete_char()
|
||||
self.qle.del_.assert_called_with()
|
||||
|
||||
def test_rl_backward_delete_char(self, qapp):
|
||||
def test_rl_backward_delete_char(self, mocked_qapp):
|
||||
"""Test rl_backward_delete_char."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_backward_delete_char()
|
||||
self.qle.backspace.assert_called_with()
|
||||
|
||||
def test_rl_unix_line_discard(self, qapp):
|
||||
def test_rl_unix_line_discard(self, mocked_qapp):
|
||||
"""Set a selected text, delete it, see if it comes back with yank."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self._set_selected_text("delete test")
|
||||
self.bridge.rl_unix_line_discard()
|
||||
self.qle.home.assert_called_with(True)
|
||||
self.assertEqual(self.bridge._deleted[self.qle], "delete test")
|
||||
assert self.bridge._deleted[self.qle] == "delete test"
|
||||
self.qle.del_.assert_called_with()
|
||||
self.bridge.rl_yank()
|
||||
self.qle.insert.assert_called_with("delete test")
|
||||
|
||||
def test_rl_kill_line(self, qapp):
|
||||
def test_rl_kill_line(self, mocked_qapp):
|
||||
"""Set a selected text, delete it, see if it comes back with yank."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self._set_selected_text("delete test")
|
||||
self.bridge.rl_kill_line()
|
||||
self.qle.end.assert_called_with(True)
|
||||
self.assertEqual(self.bridge._deleted[self.qle], "delete test")
|
||||
assert self.bridge._deleted[self.qle] == "delete test"
|
||||
self.qle.del_.assert_called_with()
|
||||
self.bridge.rl_yank()
|
||||
self.qle.insert.assert_called_with("delete test")
|
||||
|
||||
def test_rl_unix_word_rubout(self, qapp):
|
||||
def test_rl_unix_word_rubout(self, mocked_qapp):
|
||||
"""Set a selected text, delete it, see if it comes back with yank."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self._set_selected_text("delete test")
|
||||
self.bridge.rl_unix_word_rubout()
|
||||
self.qle.cursorWordBackward.assert_called_with(True)
|
||||
self.assertEqual(self.bridge._deleted[self.qle], "delete test")
|
||||
assert self.bridge._deleted[self.qle] == "delete test"
|
||||
self.qle.del_.assert_called_with()
|
||||
self.bridge.rl_yank()
|
||||
self.qle.insert.assert_called_with("delete test")
|
||||
|
||||
def test_rl_kill_word(self, qapp):
|
||||
def test_rl_kill_word(self, mocked_qapp):
|
||||
"""Set a selected text, delete it, see if it comes back with yank."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self._set_selected_text("delete test")
|
||||
self.bridge.rl_kill_word()
|
||||
self.qle.cursorWordForward.assert_called_with(True)
|
||||
self.assertEqual(self.bridge._deleted[self.qle], "delete test")
|
||||
assert self.bridge._deleted[self.qle] == "delete test"
|
||||
self.qle.del_.assert_called_with()
|
||||
self.bridge.rl_yank()
|
||||
self.qle.insert.assert_called_with("delete test")
|
||||
|
||||
def test_rl_yank_no_text(self, qapp):
|
||||
def test_rl_yank_no_text(self, mocked_qapp):
|
||||
"""Test yank without having deleted anything."""
|
||||
qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
mocked_qapp.focusWidget = mock.Mock(return_value=self.qle)
|
||||
self.bridge.rl_yank()
|
||||
self.assertFalse(self.qle.insert.called)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert not self.qle.insert.called
|
@ -21,6 +21,8 @@
|
||||
|
||||
"""Fake objects/stubs."""
|
||||
|
||||
import logging
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QPoint, QProcess, QObject
|
||||
@ -37,8 +39,8 @@ class ConfigStub:
|
||||
data: The config data to return.
|
||||
"""
|
||||
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
def __init__(self, data=None):
|
||||
self.data = data or {}
|
||||
|
||||
def section(self, name):
|
||||
"""Get a section from the config.
|
||||
@ -257,7 +259,7 @@ class FakeTimer(QObject):
|
||||
def setSingleShot(self, singleshot):
|
||||
self._singleshot = singleshot
|
||||
|
||||
def singleShot(self):
|
||||
def isSingleShot(self):
|
||||
return self._singleshot
|
||||
|
||||
def start(self):
|
||||
@ -268,3 +270,20 @@ class FakeTimer(QObject):
|
||||
|
||||
def isActive(self):
|
||||
return self._started
|
||||
|
||||
|
||||
class MessageModule:
|
||||
|
||||
"""A drop-in replacement for qutebrowser.utils.message."""
|
||||
|
||||
def error(self, _win_id, message, _immediately=False):
|
||||
"""Log an error to the message logger."""
|
||||
logging.getLogger('message').error(message)
|
||||
|
||||
def warning(self, _win_id, message, _immediately=False):
|
||||
"""Log a warning to the message logger."""
|
||||
logging.getLogger('message').warning(message)
|
||||
|
||||
def info(self, _win_id, message, _immediately=True):
|
||||
"""Log an info message to the message logger."""
|
||||
logging.getLogger('message').info(message)
|
107
tests/test_stubs.py
Normal file
107
tests/test_stubs.py
Normal file
@ -0,0 +1,107 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
"""Test test stubs."""
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def timer(stubs):
|
||||
return stubs.FakeTimer()
|
||||
|
||||
|
||||
def test_timeout(timer):
|
||||
"""Test whether timeout calls the functions."""
|
||||
func = mock.Mock()
|
||||
func2 = mock.Mock()
|
||||
timer.timeout.connect(func)
|
||||
timer.timeout.connect(func2)
|
||||
assert not func.called
|
||||
assert not func2.called
|
||||
timer.timeout.emit()
|
||||
func.assert_called_once_with()
|
||||
func2.assert_called_once_with()
|
||||
|
||||
|
||||
def test_disconnect_all(timer):
|
||||
"""Test disconnect without arguments."""
|
||||
func = mock.Mock()
|
||||
timer.timeout.connect(func)
|
||||
timer.timeout.disconnect()
|
||||
timer.timeout.emit()
|
||||
assert not func.called
|
||||
|
||||
|
||||
def test_disconnect_one(timer):
|
||||
"""Test disconnect with a single argument."""
|
||||
func = mock.Mock()
|
||||
timer.timeout.connect(func)
|
||||
timer.timeout.disconnect(func)
|
||||
timer.timeout.emit()
|
||||
assert not func.called
|
||||
|
||||
|
||||
def test_disconnect_all_invalid(timer):
|
||||
"""Test disconnecting with no connections."""
|
||||
with pytest.raises(TypeError):
|
||||
timer.timeout.disconnect()
|
||||
|
||||
|
||||
def test_disconnect_one_invalid(timer):
|
||||
"""Test disconnecting with an invalid connection."""
|
||||
func1 = mock.Mock()
|
||||
func2 = mock.Mock()
|
||||
timer.timeout.connect(func1)
|
||||
with pytest.raises(TypeError):
|
||||
timer.timeout.disconnect(func2)
|
||||
assert not func1.called
|
||||
assert not func2.called
|
||||
timer.timeout.emit()
|
||||
func1.assert_called_once_with()
|
||||
|
||||
|
||||
def test_singleshot(timer):
|
||||
"""Test setting singleShot."""
|
||||
assert not timer.isSingleShot()
|
||||
timer.setSingleShot(True)
|
||||
assert timer.isSingleShot()
|
||||
timer.start()
|
||||
assert timer.isActive()
|
||||
timer.timeout.emit()
|
||||
assert not timer.isActive()
|
||||
|
||||
|
||||
def test_active(timer):
|
||||
"""Test isActive."""
|
||||
assert not timer.isActive()
|
||||
timer.start()
|
||||
assert timer.isActive()
|
||||
timer.stop()
|
||||
assert not timer.isActive()
|
||||
|
||||
|
||||
def test_interval(timer):
|
||||
"""Test setting an interval."""
|
||||
assert timer.interval() == 0
|
||||
timer.setInterval(1000)
|
||||
assert timer.interval() == 1000
|
@ -42,4 +42,4 @@ def test_log_time(caplog):
|
||||
assert match
|
||||
|
||||
duration = float(match.group(1))
|
||||
assert 0.09 <= duration <= 0.11
|
||||
assert 0.08 <= duration <= 0.12
|
@ -21,7 +21,6 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QStyle, QFrame
|
||||
|
||||
from qutebrowser.utils import debug
|
@ -21,12 +21,11 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.test import stubs
|
||||
from qutebrowser.utils import debug
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def signal():
|
||||
def signal(stubs):
|
||||
"""Fixture to provide a faked pyqtSignal."""
|
||||
return stubs.FakeSignal()
|
||||
|
116
tests/utils/test_standarddir.py
Normal file
116
tests/utils/test_standarddir.py
Normal file
@ -0,0 +1,116 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-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/>.
|
||||
|
||||
"""Tests for qutebrowser.utils.standarddir."""
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
import pytest
|
||||
|
||||
from qutebrowser.utils import standarddir
|
||||
|
||||
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def change_qapp_name():
|
||||
"""Change the name of the QApplication instance.
|
||||
|
||||
This changes the applicationName for all tests in this module to
|
||||
"qutebrowser_test".
|
||||
"""
|
||||
old_name = QApplication.instance().applicationName()
|
||||
QApplication.instance().setApplicationName('qutebrowser_test')
|
||||
yield
|
||||
QApplication.instance().setApplicationName(old_name)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("linux"),
|
||||
reason="requires Linux")
|
||||
class TestGetStandardDirLinux:
|
||||
|
||||
"""Tests for standarddir under Linux."""
|
||||
|
||||
def test_data_explicit(self, monkeypatch, tmpdir):
|
||||
"""Test data dir with XDG_DATA_HOME explicitly set."""
|
||||
monkeypatch.setenv('XDG_DATA_HOME', str(tmpdir))
|
||||
standarddir.init(None)
|
||||
assert standarddir.data() == str(tmpdir / 'qutebrowser_test')
|
||||
|
||||
def test_config_explicit(self, monkeypatch, tmpdir):
|
||||
"""Test config dir with XDG_CONFIG_HOME explicitly set."""
|
||||
monkeypatch.setenv('XDG_CONFIG_HOME', str(tmpdir))
|
||||
standarddir.init(None)
|
||||
assert standarddir.config() == str(tmpdir / 'qutebrowser_test')
|
||||
|
||||
def test_cache_explicit(self, monkeypatch, tmpdir):
|
||||
"""Test cache dir with XDG_CACHE_HOME explicitly set."""
|
||||
monkeypatch.setenv('XDG_CACHE_HOME', str(tmpdir))
|
||||
standarddir.init(None)
|
||||
assert standarddir.cache() == str(tmpdir / 'qutebrowser_test')
|
||||
|
||||
def test_data(self, monkeypatch, tmpdir):
|
||||
"""Test data dir with XDG_DATA_HOME not set."""
|
||||
monkeypatch.setenv('HOME', str(tmpdir))
|
||||
monkeypatch.delenv('XDG_DATA_HOME', raising=False)
|
||||
standarddir.init(None)
|
||||
expected = tmpdir / '.local' / 'share' / 'qutebrowser_test'
|
||||
assert standarddir.data() == str(expected)
|
||||
|
||||
def test_config(self, monkeypatch, tmpdir):
|
||||
"""Test config dir with XDG_CONFIG_HOME not set."""
|
||||
monkeypatch.setenv('HOME', str(tmpdir))
|
||||
monkeypatch.delenv('XDG_CONFIG_HOME', raising=False)
|
||||
standarddir.init(None)
|
||||
expected = tmpdir / '.config' / 'qutebrowser_test'
|
||||
assert standarddir.config() == str(expected)
|
||||
|
||||
def test_cache(self, monkeypatch, tmpdir):
|
||||
"""Test cache dir with XDG_CACHE_HOME not set."""
|
||||
monkeypatch.setenv('HOME', str(tmpdir))
|
||||
monkeypatch.delenv('XDG_CACHE_HOME', raising=False)
|
||||
standarddir.init(None)
|
||||
expected = tmpdir / '.cache' / 'qutebrowser_test'
|
||||
assert standarddir.cache() == expected
|
||||
|
||||
|
||||
@pytest.mark.skipif(not sys.platform.startswith("win"),
|
||||
reason="requires Windows")
|
||||
class TestGetStandardDirWindows:
|
||||
|
||||
"""Tests for standarddir under Windows."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_standarddir(self):
|
||||
standarddir.init(None)
|
||||
|
||||
def test_data(self):
|
||||
"""Test data dir."""
|
||||
expected = ['qutebrowser_test', 'data']
|
||||
assert standarddir.data().split(os.sep)[-2:] == expected
|
||||
|
||||
def test_config(self):
|
||||
"""Test config dir."""
|
||||
assert standarddir.config().split(os.sep)[-1] == 'qutebrowser_test'
|
||||
|
||||
def test_cache(self):
|
||||
"""Test cache dir."""
|
||||
expected = ['qutebrowser_test', 'cache']
|
||||
assert standarddir.cache().split(os.sep)[-2:] == expected
|
@ -21,13 +21,10 @@
|
||||
|
||||
"""Tests for qutebrowser.utils.urlutils."""
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import QUrl
|
||||
import pytest
|
||||
|
||||
from qutebrowser.utils import urlutils
|
||||
from qutebrowser.test import stubs
|
||||
|
||||
|
||||
def get_config_stub(auto_search=True):
|
||||
@ -45,7 +42,7 @@ def get_config_stub(auto_search=True):
|
||||
}
|
||||
|
||||
|
||||
class SpecialURLTests(unittest.TestCase):
|
||||
class TestSpecialURL:
|
||||
|
||||
"""Test is_special_url.
|
||||
|
||||
@ -65,65 +62,67 @@ class SpecialURLTests(unittest.TestCase):
|
||||
'www.qutebrowser.org'
|
||||
)
|
||||
|
||||
def test_special_urls(self):
|
||||
@pytest.mark.parametrize('url', SPECIAL_URLS)
|
||||
def test_special_urls(self, url):
|
||||
"""Test special URLs."""
|
||||
for url in self.SPECIAL_URLS:
|
||||
with self.subTest(url=url):
|
||||
u = QUrl(url)
|
||||
self.assertTrue(urlutils.is_special_url(u))
|
||||
u = QUrl(url)
|
||||
assert urlutils.is_special_url(u)
|
||||
|
||||
def test_normal_urls(self):
|
||||
@pytest.mark.parametrize('url', NORMAL_URLS)
|
||||
def test_normal_urls(self, url):
|
||||
"""Test non-special URLs."""
|
||||
for url in self.NORMAL_URLS:
|
||||
with self.subTest(url=url):
|
||||
u = QUrl(url)
|
||||
self.assertFalse(urlutils.is_special_url(u))
|
||||
u = QUrl(url)
|
||||
assert not urlutils.is_special_url(u)
|
||||
|
||||
|
||||
@mock.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub()))
|
||||
class SearchUrlTests(unittest.TestCase):
|
||||
class TestSearchUrl:
|
||||
|
||||
"""Test _get_search_url."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_config(self, stubs, mocker):
|
||||
"""Fixture to patch urlutils.config with a stub."""
|
||||
mocker.patch('qutebrowser.utils.urlutils.config',
|
||||
new=stubs.ConfigStub(get_config_stub()))
|
||||
|
||||
def test_default_engine(self):
|
||||
"""Test default search engine."""
|
||||
url = urlutils._get_search_url('testfoo')
|
||||
self.assertEqual(url.host(), 'www.example.com')
|
||||
self.assertEqual(url.query(), 'q=testfoo')
|
||||
assert url.host() == 'www.example.com'
|
||||
assert url.query() == 'q=testfoo'
|
||||
|
||||
def test_engine_pre(self):
|
||||
"""Test search engine name with one word."""
|
||||
url = urlutils._get_search_url('test testfoo')
|
||||
self.assertEqual(url.host(), 'www.qutebrowser.org')
|
||||
self.assertEqual(url.query(), 'q=testfoo')
|
||||
assert url.host() == 'www.qutebrowser.org'
|
||||
assert url.query() == 'q=testfoo'
|
||||
|
||||
def test_engine_pre_multiple_words(self):
|
||||
"""Test search engine name with multiple words."""
|
||||
url = urlutils._get_search_url('test testfoo bar foo')
|
||||
self.assertEqual(url.host(), 'www.qutebrowser.org')
|
||||
self.assertEqual(url.query(), 'q=testfoo bar foo')
|
||||
assert url.host() == 'www.qutebrowser.org'
|
||||
assert url.query() == 'q=testfoo bar foo'
|
||||
|
||||
def test_engine_pre_whitespace_at_end(self):
|
||||
"""Test search engine name with one word and whitespace."""
|
||||
url = urlutils._get_search_url('test testfoo ')
|
||||
self.assertEqual(url.host(), 'www.qutebrowser.org')
|
||||
self.assertEqual(url.query(), 'q=testfoo')
|
||||
assert url.host() == 'www.qutebrowser.org'
|
||||
assert url.query() == 'q=testfoo'
|
||||
|
||||
def test_engine_with_bang_pre(self):
|
||||
"""Test search engine with a prepended !bang."""
|
||||
url = urlutils._get_search_url('!python testfoo')
|
||||
self.assertEqual(url.host(), 'www.example.com')
|
||||
self.assertEqual(url.query(), 'q=%21python testfoo')
|
||||
assert url.host() == 'www.example.com'
|
||||
assert url.query() == 'q=%21python testfoo'
|
||||
|
||||
def test_engine_wrong(self):
|
||||
"""Test with wrong search engine."""
|
||||
url = urlutils._get_search_url('blub testfoo')
|
||||
self.assertEqual(url.host(), 'www.example.com')
|
||||
self.assertEqual(url.query(), 'q=blub testfoo')
|
||||
assert url.host() == 'www.example.com'
|
||||
assert url.query() == 'q=blub testfoo'
|
||||
|
||||
|
||||
class IsUrlTests(unittest.TestCase):
|
||||
class TestIsUrl:
|
||||
|
||||
"""Tests for is_url.
|
||||
|
||||
@ -158,87 +157,72 @@ class IsUrlTests(unittest.TestCase):
|
||||
'foo::bar',
|
||||
)
|
||||
|
||||
@mock.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub('naive')))
|
||||
def test_urls(self):
|
||||
@pytest.mark.parametrize('url', URLS)
|
||||
def test_urls(self, mocker, stubs, url):
|
||||
"""Test things which are URLs."""
|
||||
for url in self.URLS:
|
||||
with self.subTest(url=url):
|
||||
self.assertTrue(urlutils.is_url(url), url)
|
||||
mocker.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub('naive')))
|
||||
assert urlutils.is_url(url), url
|
||||
|
||||
@mock.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub('naive')))
|
||||
def test_not_urls(self):
|
||||
@pytest.mark.parametrize('url', NOT_URLS)
|
||||
def test_not_urls(self, mocker, stubs, url):
|
||||
"""Test things which are not URLs."""
|
||||
for url in self.NOT_URLS:
|
||||
with self.subTest(url=url):
|
||||
self.assertFalse(urlutils.is_url(url), url)
|
||||
mocker.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub('naive')))
|
||||
assert not urlutils.is_url(url), url
|
||||
|
||||
@mock.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub(True)))
|
||||
def test_search_autosearch(self):
|
||||
@pytest.mark.parametrize('autosearch', [True, False])
|
||||
def test_search_autosearch(self, mocker, stubs, autosearch):
|
||||
"""Test explicit search with auto-search=True."""
|
||||
self.assertFalse(urlutils.is_url('test foo'))
|
||||
|
||||
@mock.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub(False)))
|
||||
def test_search_no_autosearch(self):
|
||||
"""Test explicit search with auto-search=False."""
|
||||
self.assertFalse(urlutils.is_url('test foo'))
|
||||
mocker.patch('qutebrowser.utils.urlutils.config', new=stubs.ConfigStub(
|
||||
get_config_stub(autosearch)))
|
||||
assert not urlutils.is_url('test foo')
|
||||
|
||||
|
||||
class QurlFromUserInputTests(unittest.TestCase):
|
||||
class TestQurlFromUserInput:
|
||||
|
||||
"""Tests for qurl_from_user_input."""
|
||||
|
||||
def test_url(self):
|
||||
"""Test a normal URL."""
|
||||
self.assertEqual(
|
||||
urlutils.qurl_from_user_input('qutebrowser.org').toString(),
|
||||
'http://qutebrowser.org')
|
||||
url = urlutils.qurl_from_user_input('qutebrowser.org')
|
||||
assert url.toString() == 'http://qutebrowser.org'
|
||||
|
||||
def test_url_http(self):
|
||||
"""Test a normal URL with http://."""
|
||||
self.assertEqual(
|
||||
urlutils.qurl_from_user_input('http://qutebrowser.org').toString(),
|
||||
'http://qutebrowser.org')
|
||||
url = urlutils.qurl_from_user_input('http://qutebrowser.org')
|
||||
assert url.toString() == 'http://qutebrowser.org'
|
||||
|
||||
def test_ipv6_bare(self):
|
||||
"""Test an IPv6 without brackets."""
|
||||
self.assertEqual(urlutils.qurl_from_user_input('::1/foo').toString(),
|
||||
'http://[::1]/foo')
|
||||
url = urlutils.qurl_from_user_input('::1/foo')
|
||||
assert url.toString() == 'http://[::1]/foo'
|
||||
|
||||
def test_ipv6(self):
|
||||
"""Test an IPv6 with brackets."""
|
||||
self.assertEqual(urlutils.qurl_from_user_input('[::1]/foo').toString(),
|
||||
'http://[::1]/foo')
|
||||
url = urlutils.qurl_from_user_input('[::1]/foo')
|
||||
assert url.toString() == 'http://[::1]/foo'
|
||||
|
||||
def test_ipv6_http(self):
|
||||
"""Test an IPv6 with http:// and brackets."""
|
||||
self.assertEqual(
|
||||
urlutils.qurl_from_user_input('http://[::1]').toString(),
|
||||
'http://[::1]')
|
||||
url = urlutils.qurl_from_user_input('http://[::1]')
|
||||
assert url.toString() == 'http://[::1]'
|
||||
|
||||
|
||||
class FilenameFromUrlTests(unittest.TestCase):
|
||||
class TestFilenameFromUrl:
|
||||
|
||||
"""Tests for filename_from_url."""
|
||||
|
||||
def test_invalid_url(self):
|
||||
"""Test with an invalid QUrl."""
|
||||
self.assertEqual(urlutils.filename_from_url(QUrl()), None)
|
||||
assert urlutils.filename_from_url(QUrl()) is None
|
||||
|
||||
def test_url_path(self):
|
||||
"""Test with an URL with path."""
|
||||
url = QUrl('http://qutebrowser.org/test.html')
|
||||
self.assertEqual(urlutils.filename_from_url(url), 'test.html')
|
||||
assert urlutils.filename_from_url(url) == 'test.html'
|
||||
|
||||
def test_url_host(self):
|
||||
"""Test with an URL with no path."""
|
||||
url = QUrl('http://qutebrowser.org/')
|
||||
self.assertEqual(urlutils.filename_from_url(url),
|
||||
'qutebrowser.org.html')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert urlutils.filename_from_url(url) == 'qutebrowser.org.html'
|
@ -21,15 +21,14 @@
|
||||
|
||||
import sys
|
||||
import enum
|
||||
import unittest
|
||||
import datetime
|
||||
import os.path
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QColor
|
||||
import pytest
|
||||
|
||||
from qutebrowser.utils import utils, qtutils
|
||||
from qutebrowser.test import helpers
|
||||
|
||||
|
||||
class Color(QColor):
|
||||
@ -42,7 +41,7 @@ class Color(QColor):
|
||||
alpha=self.alpha())
|
||||
|
||||
|
||||
class ElidingTests(unittest.TestCase):
|
||||
class TestEliding:
|
||||
|
||||
"""Test elide."""
|
||||
|
||||
@ -50,33 +49,33 @@ class ElidingTests(unittest.TestCase):
|
||||
|
||||
def test_too_small(self):
|
||||
"""Test eliding to 0 chars which should fail."""
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
utils.elide('foo', 0)
|
||||
|
||||
def test_length_one(self):
|
||||
"""Test eliding to 1 char which should yield ..."""
|
||||
self.assertEqual(utils.elide('foo', 1), self.ELLIPSIS)
|
||||
assert utils.elide('foo', 1) == self.ELLIPSIS
|
||||
|
||||
def test_fits(self):
|
||||
"""Test eliding with a string which fits exactly."""
|
||||
self.assertEqual(utils.elide('foo', 3), 'foo')
|
||||
assert utils.elide('foo', 3) == 'foo'
|
||||
|
||||
def test_elided(self):
|
||||
"""Test eliding with a string which should get elided."""
|
||||
self.assertEqual(utils.elide('foobar', 3), 'fo' + self.ELLIPSIS)
|
||||
assert utils.elide('foobar', 3) == 'fo' + self.ELLIPSIS
|
||||
|
||||
|
||||
class ReadFileTests(unittest.TestCase):
|
||||
class TestReadFile:
|
||||
|
||||
"""Test read_file."""
|
||||
|
||||
def test_readfile(self):
|
||||
"""Read a test file."""
|
||||
content = utils.read_file(os.path.join('test', 'testfile'))
|
||||
self.assertEqual(content.splitlines()[0], "Hello World!")
|
||||
content = utils.read_file(os.path.join('utils', 'testfile'))
|
||||
assert content.splitlines()[0] == "Hello World!"
|
||||
|
||||
|
||||
class InterpolateColorTests(unittest.TestCase):
|
||||
class TestInterpolateColor:
|
||||
|
||||
"""Tests for interpolate_color.
|
||||
|
||||
@ -85,30 +84,31 @@ class InterpolateColorTests(unittest.TestCase):
|
||||
white: The Color black as a valid Color for tests.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.white = Color('white')
|
||||
self.black = Color('black')
|
||||
|
||||
def test_invalid_start(self):
|
||||
"""Test an invalid start color."""
|
||||
with self.assertRaises(qtutils.QtValueError):
|
||||
with pytest.raises(qtutils.QtValueError):
|
||||
utils.interpolate_color(Color(), self.white, 0)
|
||||
|
||||
def test_invalid_end(self):
|
||||
"""Test an invalid end color."""
|
||||
with self.assertRaises(qtutils.QtValueError):
|
||||
with pytest.raises(qtutils.QtValueError):
|
||||
utils.interpolate_color(self.white, Color(), 0)
|
||||
|
||||
def test_invalid_percentage(self):
|
||||
"""Test an invalid percentage."""
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
utils.interpolate_color(self.white, self.white, -1)
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
utils.interpolate_color(self.white, self.white, 101)
|
||||
|
||||
def test_invalid_colorspace(self):
|
||||
"""Test an invalid colorspace."""
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
utils.interpolate_color(self.white, self.black, 10, QColor.Cmyk)
|
||||
|
||||
def test_valid_percentages_rgb(self):
|
||||
@ -116,30 +116,30 @@ class InterpolateColorTests(unittest.TestCase):
|
||||
white = utils.interpolate_color(self.white, self.black, 0, QColor.Rgb)
|
||||
black = utils.interpolate_color(self.white, self.black, 100,
|
||||
QColor.Rgb)
|
||||
self.assertEqual(Color(white), self.white)
|
||||
self.assertEqual(Color(black), self.black)
|
||||
assert Color(white) == self.white
|
||||
assert Color(black) == self.black
|
||||
|
||||
def test_valid_percentages_hsv(self):
|
||||
"""Test 0% and 100% in the HSV colorspace."""
|
||||
white = utils.interpolate_color(self.white, self.black, 0, QColor.Hsv)
|
||||
black = utils.interpolate_color(self.white, self.black, 100,
|
||||
QColor.Hsv)
|
||||
self.assertEqual(Color(white), self.white)
|
||||
self.assertEqual(Color(black), self.black)
|
||||
assert Color(white) == self.white
|
||||
assert Color(black) == self.black
|
||||
|
||||
def test_valid_percentages_hsl(self):
|
||||
"""Test 0% and 100% in the HSL colorspace."""
|
||||
white = utils.interpolate_color(self.white, self.black, 0, QColor.Hsl)
|
||||
black = utils.interpolate_color(self.white, self.black, 100,
|
||||
QColor.Hsl)
|
||||
self.assertEqual(Color(white), self.white)
|
||||
self.assertEqual(Color(black), self.black)
|
||||
assert Color(white) == self.white
|
||||
assert Color(black) == self.black
|
||||
|
||||
def test_interpolation_rgb(self):
|
||||
"""Test an interpolation in the RGB colorspace."""
|
||||
color = utils.interpolate_color(Color(0, 40, 100), Color(0, 20, 200),
|
||||
50, QColor.Rgb)
|
||||
self.assertEqual(Color(color), Color(0, 30, 150))
|
||||
assert Color(color) == Color(0, 30, 150)
|
||||
|
||||
def test_interpolation_hsv(self):
|
||||
"""Test an interpolation in the HSV colorspace."""
|
||||
@ -150,7 +150,7 @@ class InterpolateColorTests(unittest.TestCase):
|
||||
color = utils.interpolate_color(start, stop, 50, QColor.Hsv)
|
||||
expected = Color()
|
||||
expected.setHsv(0, 30, 150)
|
||||
self.assertEqual(Color(color), expected)
|
||||
assert Color(color) == expected
|
||||
|
||||
def test_interpolation_hsl(self):
|
||||
"""Test an interpolation in the HSL colorspace."""
|
||||
@ -161,10 +161,10 @@ class InterpolateColorTests(unittest.TestCase):
|
||||
color = utils.interpolate_color(start, stop, 50, QColor.Hsl)
|
||||
expected = Color()
|
||||
expected.setHsl(0, 30, 150)
|
||||
self.assertEqual(Color(color), expected)
|
||||
assert Color(color) == expected
|
||||
|
||||
|
||||
class FormatSecondsTests(unittest.TestCase):
|
||||
class TestFormatSeconds:
|
||||
|
||||
"""Tests for format_seconds.
|
||||
|
||||
@ -186,14 +186,13 @@ class FormatSecondsTests(unittest.TestCase):
|
||||
(36000, '10:00:00'),
|
||||
]
|
||||
|
||||
def test_format_seconds(self):
|
||||
@pytest.mark.parametrize('seconds, out', TESTS)
|
||||
def test_format_seconds(self, seconds, out):
|
||||
"""Test format_seconds with several tests."""
|
||||
for seconds, out in self.TESTS:
|
||||
with self.subTest(seconds=seconds):
|
||||
self.assertEqual(utils.format_seconds(seconds), out)
|
||||
assert utils.format_seconds(seconds) == out
|
||||
|
||||
|
||||
class FormatTimedeltaTests(unittest.TestCase):
|
||||
class TestFormatTimedelta:
|
||||
|
||||
"""Tests for format_timedelta.
|
||||
|
||||
@ -217,14 +216,13 @@ class FormatTimedeltaTests(unittest.TestCase):
|
||||
(datetime.timedelta(seconds=36000), '10h'),
|
||||
]
|
||||
|
||||
def test_format_seconds(self):
|
||||
@pytest.mark.parametrize('td, out', TESTS)
|
||||
def test_format_seconds(self, td, out):
|
||||
"""Test format_seconds with several tests."""
|
||||
for td, out in self.TESTS:
|
||||
with self.subTest(td=td):
|
||||
self.assertEqual(utils.format_timedelta(td), out)
|
||||
assert utils.format_timedelta(td) == out
|
||||
|
||||
|
||||
class FormatSizeTests(unittest.TestCase):
|
||||
class TestFormatSize:
|
||||
|
||||
"""Tests for format_size.
|
||||
|
||||
@ -244,122 +242,117 @@ class FormatSizeTests(unittest.TestCase):
|
||||
(None, '?.??'),
|
||||
]
|
||||
|
||||
def test_format_size(self):
|
||||
KILO_TESTS = [(999, '999.00'), (1000, '1.00k'), (1010, '1.01k')]
|
||||
|
||||
@pytest.mark.parametrize('size, out', TESTS)
|
||||
def test_format_size(self, size, out):
|
||||
"""Test format_size with several tests."""
|
||||
for size, out in self.TESTS:
|
||||
with self.subTest(size=size):
|
||||
self.assertEqual(utils.format_size(size), out)
|
||||
assert utils.format_size(size) == out
|
||||
|
||||
def test_suffix(self):
|
||||
@pytest.mark.parametrize('size, out', TESTS)
|
||||
def test_suffix(self, size, out):
|
||||
"""Test the suffix option."""
|
||||
for size, out in self.TESTS:
|
||||
with self.subTest(size=size):
|
||||
self.assertEqual(utils.format_size(size, suffix='B'),
|
||||
out + 'B')
|
||||
assert utils.format_size(size, suffix='B') == out + 'B'
|
||||
|
||||
def test_base(self):
|
||||
@pytest.mark.parametrize('size, out', KILO_TESTS)
|
||||
def test_base(self, size, out):
|
||||
"""Test with an alternative base."""
|
||||
kilo_tests = [(999, '999.00'), (1000, '1.00k'), (1010, '1.01k')]
|
||||
for size, out in kilo_tests:
|
||||
with self.subTest(size=size):
|
||||
self.assertEqual(utils.format_size(size, base=1000), out)
|
||||
assert utils.format_size(size, base=1000) == out
|
||||
|
||||
|
||||
class KeyToStringTests(unittest.TestCase):
|
||||
class TestKeyToString:
|
||||
|
||||
"""Test key_to_string."""
|
||||
|
||||
def test_unicode_garbage_keys(self):
|
||||
"""Test a special key where QKeyEvent::toString works incorrectly."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_Blue), 'Blue')
|
||||
assert utils.key_to_string(Qt.Key_Blue) == 'Blue'
|
||||
|
||||
def test_backtab(self):
|
||||
"""Test if backtab is normalized to tab correctly."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_Backtab), 'Tab')
|
||||
assert utils.key_to_string(Qt.Key_Backtab) == 'Tab'
|
||||
|
||||
def test_escape(self):
|
||||
"""Test if escape is normalized to escape correctly."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_Escape), 'Escape')
|
||||
assert utils.key_to_string(Qt.Key_Escape) == 'Escape'
|
||||
|
||||
def test_letter(self):
|
||||
"""Test a simple letter key."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_A), 'A')
|
||||
assert utils.key_to_string(Qt.Key_A) == 'A'
|
||||
|
||||
def test_unicode(self):
|
||||
"""Test a printable unicode key."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_degree), '°')
|
||||
assert utils.key_to_string(Qt.Key_degree) == '°'
|
||||
|
||||
def test_special(self):
|
||||
"""Test a non-printable key handled by QKeyEvent::toString."""
|
||||
self.assertEqual(utils.key_to_string(Qt.Key_F1), 'F1')
|
||||
assert utils.key_to_string(Qt.Key_F1) == 'F1'
|
||||
|
||||
|
||||
class KeyEventToStringTests(unittest.TestCase):
|
||||
class TestKeyEventToString:
|
||||
|
||||
"""Test keyevent_to_string."""
|
||||
|
||||
def test_only_control(self):
|
||||
"""Test keyevent when only control is pressed."""
|
||||
evt = helpers.fake_keyevent(key=Qt.Key_Control,
|
||||
def test_only_control(self, fake_keyevent_factory):
|
||||
"""Test keyeevent when only control is pressed."""
|
||||
evt = fake_keyevent_factory(key=Qt.Key_Control,
|
||||
modifiers=Qt.ControlModifier)
|
||||
self.assertIsNone(utils.keyevent_to_string(evt))
|
||||
assert utils.keyevent_to_string(evt) is None
|
||||
|
||||
def test_only_hyper_l(self):
|
||||
"""Test keyevent when only Hyper_L is pressed."""
|
||||
evt = helpers.fake_keyevent(key=Qt.Key_Hyper_L,
|
||||
def test_only_hyper_l(self, fake_keyevent_factory):
|
||||
"""Test keyeevent when only Hyper_L is pressed."""
|
||||
evt = fake_keyevent_factory(key=Qt.Key_Hyper_L,
|
||||
modifiers=Qt.MetaModifier)
|
||||
self.assertIsNone(utils.keyevent_to_string(evt))
|
||||
assert utils.keyevent_to_string(evt) is None
|
||||
|
||||
def test_only_key(self):
|
||||
def test_only_key(self, fake_keyevent_factory):
|
||||
"""Test with a simple key pressed."""
|
||||
evt = helpers.fake_keyevent(key=Qt.Key_A)
|
||||
self.assertEqual(utils.keyevent_to_string(evt), 'A')
|
||||
evt = fake_keyevent_factory(key=Qt.Key_A)
|
||||
assert utils.keyevent_to_string(evt) == 'A'
|
||||
|
||||
def test_key_and_modifier(self):
|
||||
def test_key_and_modifier(self, fake_keyevent_factory):
|
||||
"""Test with key and modifier pressed."""
|
||||
evt = helpers.fake_keyevent(key=Qt.Key_A, modifiers=Qt.ControlModifier)
|
||||
self.assertEqual(utils.keyevent_to_string(evt), 'Ctrl+A')
|
||||
evt = fake_keyevent_factory(key=Qt.Key_A, modifiers=Qt.ControlModifier)
|
||||
assert utils.keyevent_to_string(evt) == 'Ctrl+A'
|
||||
|
||||
def test_key_and_modifiers(self):
|
||||
def test_key_and_modifiers(self, fake_keyevent_factory):
|
||||
"""Test with key and multiple modifier pressed."""
|
||||
evt = helpers.fake_keyevent(
|
||||
evt = fake_keyevent_factory(
|
||||
key=Qt.Key_A, modifiers=(Qt.ControlModifier | Qt.AltModifier |
|
||||
Qt.MetaModifier | Qt.ShiftModifier))
|
||||
if sys.platform == 'darwin':
|
||||
self.assertEqual(utils.keyevent_to_string(evt),
|
||||
'Ctrl+Alt+Shift+A')
|
||||
assert utils.keyevent_to_string(evt) == 'Ctrl+Alt+Shift+A'
|
||||
else:
|
||||
self.assertEqual(utils.keyevent_to_string(evt),
|
||||
'Ctrl+Alt+Meta+Shift+A')
|
||||
assert utils.keyevent_to_string(evt) == 'Ctrl+Alt+Meta+Shift+A'
|
||||
|
||||
|
||||
class NormalizeTests(unittest.TestCase):
|
||||
class TestNormalize:
|
||||
|
||||
"""Test normalize_keystr."""
|
||||
|
||||
def test_normalize(self):
|
||||
STRINGS = (
|
||||
('Control+x', 'ctrl+x'),
|
||||
('Windows+x', 'meta+x'),
|
||||
('Mod1+x', 'alt+x'),
|
||||
('Mod4+x', 'meta+x'),
|
||||
('Control--', 'ctrl+-'),
|
||||
('Windows++', 'meta++'),
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize('orig, repl', STRINGS)
|
||||
def test_normalize(self, orig, repl):
|
||||
"""Test normalize with some strings."""
|
||||
strings = (
|
||||
('Control+x', 'ctrl+x'),
|
||||
('Windows+x', 'meta+x'),
|
||||
('Mod1+x', 'alt+x'),
|
||||
('Mod4+x', 'meta+x'),
|
||||
('Control--', 'ctrl+-'),
|
||||
('Windows++', 'meta++'),
|
||||
)
|
||||
for orig, repl in strings:
|
||||
with self.subTest(orig=orig):
|
||||
self.assertEqual(utils.normalize_keystr(orig), repl)
|
||||
assert utils.normalize_keystr(orig) == repl
|
||||
|
||||
|
||||
class IsEnumTests(unittest.TestCase):
|
||||
class TestIsEnum:
|
||||
|
||||
"""Test is_enum."""
|
||||
|
||||
def test_enum(self):
|
||||
"""Test is_enum with an enum."""
|
||||
e = enum.Enum('Foo', 'bar, baz')
|
||||
self.assertTrue(utils.is_enum(e))
|
||||
assert utils.is_enum(e)
|
||||
|
||||
def test_class(self):
|
||||
"""Test is_enum with a non-enum class."""
|
||||
@ -368,14 +361,15 @@ class IsEnumTests(unittest.TestCase):
|
||||
"""Test class for is_enum."""
|
||||
|
||||
pass
|
||||
self.assertFalse(utils.is_enum(Test))
|
||||
|
||||
assert not utils.is_enum(Test)
|
||||
|
||||
def test_object(self):
|
||||
"""Test is_enum with a non-enum object."""
|
||||
self.assertFalse(utils.is_enum(23))
|
||||
assert not utils.is_enum(23)
|
||||
|
||||
|
||||
class RaisesTests(unittest.TestCase):
|
||||
class TestRaises:
|
||||
|
||||
"""Test raises."""
|
||||
|
||||
@ -389,106 +383,98 @@ class RaisesTests(unittest.TestCase):
|
||||
|
||||
def test_raises_single_exc_true(self):
|
||||
"""Test raises with a single exception which gets raised."""
|
||||
self.assertTrue(utils.raises(ValueError, int, 'a'))
|
||||
assert utils.raises(ValueError, int, 'a')
|
||||
|
||||
def test_raises_single_exc_false(self):
|
||||
"""Test raises with a single exception which does not get raised."""
|
||||
self.assertFalse(utils.raises(ValueError, int, '1'))
|
||||
assert not utils.raises(ValueError, int, '1')
|
||||
|
||||
def test_raises_multiple_exc_true(self):
|
||||
"""Test raises with multiple exceptions which get raised."""
|
||||
self.assertTrue(utils.raises((ValueError, TypeError), int, 'a'))
|
||||
self.assertTrue(utils.raises((ValueError, TypeError), int, None))
|
||||
assert utils.raises((ValueError, TypeError), int, 'a')
|
||||
assert utils.raises((ValueError, TypeError), int, None)
|
||||
|
||||
def test_raises_multiple_exc_false(self):
|
||||
"""Test raises with multiple exceptions which do not get raised."""
|
||||
self.assertFalse(utils.raises((ValueError, TypeError), int, '1'))
|
||||
assert not utils.raises((ValueError, TypeError), int, '1')
|
||||
|
||||
def test_no_args_true(self):
|
||||
"""Test with no args and an exception which gets raised."""
|
||||
self.assertTrue(utils.raises(Exception, self.do_raise))
|
||||
assert utils.raises(Exception, self.do_raise)
|
||||
|
||||
def test_no_args_false(self):
|
||||
"""Test with no args and an exception which does not get raised."""
|
||||
self.assertFalse(utils.raises(Exception, self.do_nothing))
|
||||
assert not utils.raises(Exception, self.do_nothing)
|
||||
|
||||
def test_unrelated_exception(self):
|
||||
"""Test with an unrelated exception."""
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
utils.raises(ValueError, self.do_raise)
|
||||
|
||||
|
||||
class ForceEncodingTests(unittest.TestCase):
|
||||
class TestForceEncoding:
|
||||
|
||||
"""Test force_encoding."""
|
||||
|
||||
def test_fitting_ascii(self):
|
||||
"""Test with a text fitting into ASCII."""
|
||||
text = 'hello world'
|
||||
self.assertEqual(utils.force_encoding(text, 'ascii'), text)
|
||||
TESTS = [
|
||||
('hello world', 'ascii', 'hello world'),
|
||||
('hellö wörld', 'utf-8', 'hellö wörld'),
|
||||
('hellö wörld', 'ascii', 'hell? w?rld'),
|
||||
]
|
||||
|
||||
def test_fitting_utf8(self):
|
||||
"""Test with a text fitting into utf-8."""
|
||||
text = 'hellö wörld'
|
||||
self.assertEqual(utils.force_encoding(text, 'utf-8'), text)
|
||||
|
||||
def test_not_fitting_ascii(self):
|
||||
"""Test with a text not fitting into ASCII."""
|
||||
text = 'hellö wörld'
|
||||
self.assertEqual(utils.force_encoding(text, 'ascii'), 'hell? w?rld')
|
||||
@pytest.mark.parametrize('inp, enc, expected', TESTS)
|
||||
def test_fitting_ascii(self, inp, enc, expected):
|
||||
"""Test force_encoding will yield expected text."""
|
||||
assert utils.force_encoding(inp, enc) == expected
|
||||
|
||||
|
||||
class NewestSliceTests(unittest.TestCase):
|
||||
class TestNewestSlice:
|
||||
|
||||
"""Test newest_slice."""
|
||||
|
||||
def test_count_minus_two(self):
|
||||
"""Test with a count of -2."""
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
utils.newest_slice([], -2)
|
||||
|
||||
def test_count_minus_one(self):
|
||||
"""Test with a count of -1 (all elements)."""
|
||||
items = range(20)
|
||||
sliced = utils.newest_slice(items, -1)
|
||||
self.assertEqual(list(sliced), list(items))
|
||||
assert list(sliced) == list(items)
|
||||
|
||||
def test_count_zero(self):
|
||||
"""Test with a count of 0 (no elements)."""
|
||||
items = range(20)
|
||||
sliced = utils.newest_slice(items, 0)
|
||||
self.assertEqual(list(sliced), [])
|
||||
assert list(sliced) == []
|
||||
|
||||
def test_count_much_smaller(self):
|
||||
"""Test with a count which is much smaller than the iterable."""
|
||||
items = range(20)
|
||||
sliced = utils.newest_slice(items, 5)
|
||||
self.assertEqual(list(sliced), [15, 16, 17, 18, 19])
|
||||
assert list(sliced) == [15, 16, 17, 18, 19]
|
||||
|
||||
def test_count_smaller(self):
|
||||
"""Test with a count which is exactly one smaller."""
|
||||
items = range(5)
|
||||
sliced = utils.newest_slice(items, 4)
|
||||
self.assertEqual(list(sliced), [1, 2, 3, 4])
|
||||
assert list(sliced) == [1, 2, 3, 4]
|
||||
|
||||
def test_count_equal(self):
|
||||
"""Test with a count which is just as large as the iterable."""
|
||||
items = range(5)
|
||||
sliced = utils.newest_slice(items, 5)
|
||||
self.assertEqual(list(sliced), list(items))
|
||||
assert list(sliced) == list(items)
|
||||
|
||||
def test_count_bigger(self):
|
||||
"""Test with a count which is one bigger than the iterable."""
|
||||
items = range(5)
|
||||
sliced = utils.newest_slice(items, 6)
|
||||
self.assertEqual(list(sliced), list(items))
|
||||
assert list(sliced) == list(items)
|
||||
|
||||
def test_count_much_bigger(self):
|
||||
"""Test with a count which is much bigger than the iterable."""
|
||||
items = range(5)
|
||||
sliced = utils.newest_slice(items, 50)
|
||||
self.assertEqual(list(sliced), list(items))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert list(sliced) == list(items)
|
14
tox.ini
14
tox.ini
@ -20,6 +20,8 @@ deps =
|
||||
py==1.4.26
|
||||
pytest==2.7.0
|
||||
pytest-capturelog==0.7
|
||||
pytest-qt==1.3.0
|
||||
pytest-mock==0.4.2
|
||||
# We don't use {[testenv:mkvenv]commands} here because that seems to be broken
|
||||
# on Ubuntu Trusty.
|
||||
commands =
|
||||
@ -39,8 +41,8 @@ commands =
|
||||
[testenv:misc]
|
||||
commands =
|
||||
{envpython} scripts/misc_checks.py git
|
||||
{envpython} scripts/misc_checks.py vcs qutebrowser scripts
|
||||
{envpython} scripts/misc_checks.py spelling qutebrowser scripts
|
||||
{envpython} scripts/misc_checks.py vcs qutebrowser scripts tests
|
||||
{envpython} scripts/misc_checks.py spelling qutebrowser scripts tests
|
||||
|
||||
[testenv:pylint]
|
||||
skip_install = true
|
||||
@ -55,6 +57,7 @@ deps =
|
||||
commands =
|
||||
{[testenv:mkvenv]commands}
|
||||
{envdir}/bin/pylint scripts qutebrowser --rcfile=.pylintrc --output-format=colorized --reports=no
|
||||
{envpython} scripts/run_pylint_on_tests.py --rcfile=.pylintrc --output-format=colorized --reports=no
|
||||
|
||||
[testenv:pep257]
|
||||
skip_install = true
|
||||
@ -63,7 +66,7 @@ deps = pep257==0.5.0
|
||||
# D102: Docstring missing, will be handled by others
|
||||
# D209: Blank line before closing """ (removed from PEP257)
|
||||
# D402: First line should not be function's signature (false-positives)
|
||||
commands = {envpython} -m pep257 scripts qutebrowser --ignore=D102,D209,D402 '--match=(?!resources|test_content_disposition).*\.py'
|
||||
commands = {envpython} -m pep257 scripts tests qutebrowser --ignore=D102,D103,D209,D402 '--match=(?!resources|test_content_disposition).*\.py'
|
||||
|
||||
[testenv:flake8]
|
||||
skip_install = true
|
||||
@ -74,7 +77,7 @@ deps =
|
||||
flake8==2.4.0
|
||||
commands =
|
||||
{[testenv:mkvenv]commands}
|
||||
{envdir}/bin/flake8 scripts qutebrowser --config=.flake8
|
||||
{envdir}/bin/flake8 scripts tests qutebrowser --config=.flake8
|
||||
|
||||
[testenv:pyroma]
|
||||
skip_install = true
|
||||
@ -103,3 +106,6 @@ commands =
|
||||
{envpython} scripts/src2asciidoc.py
|
||||
git --no-pager diff --exit-code --stat
|
||||
{envpython} scripts/asciidoc2html.py {posargs}
|
||||
|
||||
[pytest]
|
||||
norecursedirs = .tox .venv
|
||||
|
Loading…
Reference in New Issue
Block a user