Various unittest fixes and improvements.

This commit is contained in:
Florian Bruhin 2015-02-27 12:43:54 +01:00
parent 072210c47b
commit 84643b4a39
4 changed files with 62 additions and 80 deletions

View File

@ -25,6 +25,7 @@ import logging
from qutebrowser.browser import http from qutebrowser.browser import http
from qutebrowser.test import stubs from qutebrowser.test import stubs
from qutebrowser.utils import log
DEFAULT_NAME = 'qutebrowser-download' DEFAULT_NAME = 'qutebrowser-download'
@ -48,7 +49,8 @@ class AttachmentTestCase(unittest.TestCase):
def _check_ignored(self, header): def _check_ignored(self, header):
"""Check if the passed header is ignored.""" """Check if the passed header is ignored."""
reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header}) reply = stubs.FakeNetworkReply(headers={'Content-Disposition': header})
cd_inline, cd_filename = http.parse_content_disposition(reply) with self.assertLogs(log.rfc6266, logging.ERROR):
cd_inline, cd_filename = http.parse_content_disposition(reply)
self.assertEqual(cd_filename, DEFAULT_NAME) self.assertEqual(cd_filename, DEFAULT_NAME)
self.assertTrue(cd_inline) self.assertTrue(cd_inline)
@ -93,7 +95,8 @@ class InlineTests(unittest.TestCase):
This is invalid syntax, thus the header should be ignored. This is invalid syntax, thus the header should be ignored.
""" """
self._check_ignored('"inline"') with self.assertLogs(log.rfc6266, logging.ERROR):
self._check_ignored('"inline"')
def test_inlwithasciifilename(self): def test_inlwithasciifilename(self):
"""'inline', specifying a filename of foo.html """'inline', specifying a filename of foo.html
@ -891,15 +894,5 @@ class OurTests(AttachmentTestCase):
'foo bar.html') 'foo bar.html')
def setUpModule():
"""Disable logging."""
logging.disable(logging.ERROR)
def tearDownModule():
"""Restore logging."""
logging.disable(logging.NOTSET)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -29,7 +29,7 @@ from PyQt5.QtCore import Qt
from qutebrowser.keyinput import basekeyparser from qutebrowser.keyinput import basekeyparser
from qutebrowser.test import stubs, helpers from qutebrowser.test import stubs, helpers
from qutebrowser.utils import objreg from qutebrowser.utils import objreg, log
CONFIG = {'input': {'timeout': 100}} CONFIG = {'input': {'timeout': 100}}
@ -47,17 +47,6 @@ fake_keyconfig = mock.Mock(spec=['get_bindings_for'])
fake_keyconfig.get_bindings_for.side_effect = lambda s: BINDINGS[s] fake_keyconfig.get_bindings_for.side_effect = lambda s: BINDINGS[s]
def setUpModule():
"""Mock out some imports in basekeyparser."""
basekeyparser.QObject = mock.Mock()
logging.disable(logging.WARNING)
def tearDownModule():
"""Restore mocked out stuff."""
logging.disable(logging.NOTSET)
class SplitCountTests(unittest.TestCase): class SplitCountTests(unittest.TestCase):
"""Test the _split_count method. """Test the _split_count method.
@ -101,13 +90,14 @@ class SplitCountTests(unittest.TestCase):
self.assertEqual(self.kp._split_count(), (None, '10foo')) self.assertEqual(self.kp._split_count(), (None, '10foo'))
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
new=stubs.FakeTimer)
class ReadConfigTests(unittest.TestCase): class ReadConfigTests(unittest.TestCase):
"""Test reading the config.""" """Test reading the config."""
def setUp(self): def setUp(self):
objreg.register('key-config', fake_keyconfig) objreg.register('key-config', fake_keyconfig)
basekeyparser.usertypes.Timer = mock.Mock()
def tearDown(self): def tearDown(self):
objreg.delete('key-config') objreg.delete('key-config')
@ -132,6 +122,8 @@ class ReadConfigTests(unittest.TestCase):
self.assertIn('ctrl+x', kp.special_bindings) self.assertIn('ctrl+x', kp.special_bindings)
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
new=stubs.FakeTimer)
class SpecialKeysTests(unittest.TestCase): class SpecialKeysTests(unittest.TestCase):
"""Check execute() with special keys. """Check execute() with special keys.
@ -141,15 +133,13 @@ class SpecialKeysTests(unittest.TestCase):
""" """
def setUp(self): def setUp(self):
patcher = mock.patch(
'qutebrowser.keyinput.basekeyparser.usertypes.Timer',
autospec=True)
patcher.start()
objreg.register('key-config', fake_keyconfig) objreg.register('key-config', fake_keyconfig)
self.addCleanup(patcher.stop)
self.kp = basekeyparser.BaseKeyParser(0) self.kp = basekeyparser.BaseKeyParser(0)
self.kp.execute = mock.Mock() self.kp.execute = mock.Mock()
self.kp.read_config('test') 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): def tearDown(self):
objreg.delete('key-config') objreg.delete('key-config')
@ -173,20 +163,19 @@ class SpecialKeysTests(unittest.TestCase):
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
new=stubs.FakeTimer)
class KeyChainTests(unittest.TestCase): class KeyChainTests(unittest.TestCase):
"""Test execute() with keychain support. """Test execute() with keychain support.
Attributes: Attributes:
kp: The BaseKeyParser to be tested. kp: The BaseKeyParser to be tested.
timermock: The mock to be used as timer.
""" """
def setUp(self): def setUp(self):
"""Set up mocks and read the test config.""" """Set up mocks and read the test config."""
objreg.register('key-config', fake_keyconfig) objreg.register('key-config', fake_keyconfig)
self.timermock = mock.Mock()
basekeyparser.usertypes.Timer = mock.Mock(return_value=self.timermock)
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True, self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
supports_count=False) supports_count=False)
self.kp.execute = mock.Mock() self.kp.execute = mock.Mock()
@ -222,22 +211,20 @@ class KeyChainTests(unittest.TestCase):
def test_ambigious_keychain(self): def test_ambigious_keychain(self):
"""Test ambigious keychain.""" """Test ambigious keychain."""
basekeyparser.config = stubs.ConfigStub(CONFIG) basekeyparser.config = stubs.ConfigStub(CONFIG)
timer = self.kp._ambigious_timer
self.assertFalse(timer.isActive())
# We start with 'a' where the keychain gives us an ambigious result. # We start with 'a' where the keychain gives us an ambigious result.
# Then we check if the timer has been set up correctly # Then we check if the timer has been set up correctly
self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a')) self.kp.handle(helpers.fake_keyevent(Qt.Key_A, text='a'))
self.assertFalse(self.kp.execute.called) self.assertFalse(self.kp.execute.called)
basekeyparser.usertypes.Timer.assert_called_once_with( self.assertTrue(timer.isSingleShot())
self.kp, 'ambigious-match') self.assertEqual(timer.interval(), 100)
self.timermock.setSingleShot.assert_called_once_with(True) self.assertTrue(timer.isActive())
self.timermock.setInterval.assert_called_once_with(100)
self.assertTrue(self.timermock.timeout.connect.called)
self.assertFalse(self.timermock.stop.called)
self.timermock.start.assert_called_once_with()
# Now we type an 'x' and check 'ax' has been executed and the timer # Now we type an 'x' and check 'ax' has been executed and the timer
# stopped. # stopped.
self.kp.handle(helpers.fake_keyevent(Qt.Key_X, text='x')) 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.kp.execute.assert_called_once_with('ax', self.kp.Type.chain, None)
self.timermock.stop.assert_called_once_with() self.assertFalse(timer.isActive())
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
def test_invalid_keychain(self): def test_invalid_keychain(self):
@ -247,13 +234,14 @@ class KeyChainTests(unittest.TestCase):
self.assertEqual(self.kp._keystring, '') self.assertEqual(self.kp._keystring, '')
@mock.patch('qutebrowser.keyinput.basekeyparser.usertypes.Timer',
new=stubs.FakeTimer)
class CountTests(unittest.TestCase): class CountTests(unittest.TestCase):
"""Test execute() with counts.""" """Test execute() with counts."""
def setUp(self): def setUp(self):
objreg.register('key-config', fake_keyconfig) objreg.register('key-config', fake_keyconfig)
basekeyparser.usertypes.Timer = mock.Mock()
self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True, self.kp = basekeyparser.BaseKeyParser(0, supports_chains=True,
supports_count=True) supports_count=True)
self.kp.execute = mock.Mock() self.kp.execute = mock.Mock()

View File

@ -24,7 +24,6 @@
import os import os
import os.path import os.path
import unittest import unittest
import logging
from unittest import mock from unittest import mock
from PyQt5.QtCore import QProcess from PyQt5.QtCore import QProcess
@ -33,18 +32,8 @@ from qutebrowser.misc import editor
from qutebrowser.test import stubs from qutebrowser.test import stubs
def setUpModule(): @mock.patch('qutebrowser.misc.editor.QProcess',
"""Disable logging and mock out some imports.""" new_callable=stubs.FakeQProcess)
logging.disable(logging.INFO)
editor.message = mock.Mock()
editor.QProcess = stubs.FakeQProcess
def tearDownModule():
"""Restore logging."""
logging.disable(logging.NOTSET)
class ArgTests(unittest.TestCase): class ArgTests(unittest.TestCase):
"""Test argument handling. """Test argument handling.
@ -56,14 +45,14 @@ class ArgTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.editor = editor.ExternalEditor(0) self.editor = editor.ExternalEditor(0)
def test_simple_start_args(self): def test_simple_start_args(self, _proc_mock):
"""Test starting editor without arguments.""" """Test starting editor without arguments."""
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}) {'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
self.editor._proc.start.assert_called_with("bin", []) self.editor._proc.start.assert_called_with("bin", [])
def test_start_args(self): def test_start_args(self, _proc_mock):
"""Test starting editor with static arguments.""" """Test starting editor with static arguments."""
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo', 'bar'], {'general': {'editor': ['bin', 'foo', 'bar'],
@ -71,17 +60,17 @@ class ArgTests(unittest.TestCase):
self.editor.edit("") self.editor.edit("")
self.editor._proc.start.assert_called_with("bin", ["foo", "bar"]) self.editor._proc.start.assert_called_with("bin", ["foo", "bar"])
def test_placeholder(self): def test_placeholder(self, _proc_mock):
"""Test starting editor with placeholder argument.""" """Test starting editor with placeholder argument."""
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo', '{}', 'bar'], {'general': {'editor': ['bin', 'foo', '{}', 'bar'],
'editor-encoding': 'utf-8'}}) 'editor-encoding': 'utf-8'}})
self.editor.edit("") self.editor.edit("")
filename = self.editor._filename filename = self.editor._filename
self.editor._proc.start.assert_called_with("bin", self.editor._proc.start.assert_called_with(
["foo", filename, "bar"]) "bin", ["foo", filename, "bar"])
def test_in_arg_placeholder(self): def test_in_arg_placeholder(self, _proc_mock):
"""Test starting editor with placeholder argument inside argument.""" """Test starting editor with placeholder argument inside argument."""
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': ['bin', 'foo{}bar'], {'general': {'editor': ['bin', 'foo{}bar'],
@ -93,6 +82,8 @@ class ArgTests(unittest.TestCase):
self.editor._cleanup() # pylint: disable=protected-access self.editor._cleanup() # pylint: disable=protected-access
@mock.patch('qutebrowser.misc.editor.QProcess',
new_callable=stubs.FakeQProcess)
class FileHandlingTests(unittest.TestCase): class FileHandlingTests(unittest.TestCase):
"""Test creation/deletion of tempfile. """Test creation/deletion of tempfile.
@ -106,7 +97,7 @@ class FileHandlingTests(unittest.TestCase):
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}) {'general': {'editor': [''], 'editor-encoding': 'utf-8'}})
def test_file_handling_closed_ok(self): def test_file_handling_closed_ok(self, _proc_mock):
"""Test file handling when closing with an exitstatus == 0.""" """Test file handling when closing with an exitstatus == 0."""
self.editor.edit("") self.editor.edit("")
filename = self.editor._filename filename = self.editor._filename
@ -114,7 +105,7 @@ class FileHandlingTests(unittest.TestCase):
self.editor.on_proc_closed(0, QProcess.NormalExit) self.editor.on_proc_closed(0, QProcess.NormalExit)
self.assertFalse(os.path.exists(filename)) self.assertFalse(os.path.exists(filename))
def test_file_handling_closed_error(self): def test_file_handling_closed_error(self, _proc_mock):
"""Test file handling when closing with an exitstatus != 0.""" """Test file handling when closing with an exitstatus != 0."""
self.editor.edit("") self.editor.edit("")
filename = self.editor._filename filename = self.editor._filename
@ -122,7 +113,7 @@ class FileHandlingTests(unittest.TestCase):
self.editor.on_proc_closed(1, QProcess.NormalExit) self.editor.on_proc_closed(1, QProcess.NormalExit)
self.assertFalse(os.path.exists(filename)) self.assertFalse(os.path.exists(filename))
def test_file_handling_closed_crash(self): def test_file_handling_closed_crash(self, _proc_mock):
"""Test file handling when closing with a crash.""" """Test file handling when closing with a crash."""
self.editor.edit("") self.editor.edit("")
filename = self.editor._filename filename = self.editor._filename
@ -132,6 +123,8 @@ class FileHandlingTests(unittest.TestCase):
self.assertFalse(os.path.exists(filename)) self.assertFalse(os.path.exists(filename))
@mock.patch('qutebrowser.misc.editor.QProcess',
new_callable=stubs.FakeQProcess)
class TextModifyTests(unittest.TestCase): class TextModifyTests(unittest.TestCase):
"""Tests to test if the text gets saved/loaded correctly. """Tests to test if the text gets saved/loaded correctly.
@ -167,7 +160,7 @@ class TextModifyTests(unittest.TestCase):
data = f.read() data = f.read()
return data return data
def test_empty_input(self): def test_empty_input(self, _proc_mock):
"""Test if an empty input gets modified correctly.""" """Test if an empty input gets modified correctly."""
self.editor.edit("") self.editor.edit("")
self.assertEqual(self._read(), "") self.assertEqual(self._read(), "")
@ -175,7 +168,7 @@ class TextModifyTests(unittest.TestCase):
self.editor.on_proc_closed(0, QProcess.NormalExit) self.editor.on_proc_closed(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("Hello") self.editor.editing_finished.emit.assert_called_with("Hello")
def test_simple_input(self): def test_simple_input(self, _proc_mock):
"""Test if an empty input gets modified correctly.""" """Test if an empty input gets modified correctly."""
self.editor.edit("Hello") self.editor.edit("Hello")
self.assertEqual(self._read(), "Hello") self.assertEqual(self._read(), "Hello")
@ -183,7 +176,7 @@ class TextModifyTests(unittest.TestCase):
self.editor.on_proc_closed(0, QProcess.NormalExit) self.editor.on_proc_closed(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("World") self.editor.editing_finished.emit.assert_called_with("World")
def test_umlaut(self): def test_umlaut(self, _proc_mock):
"""Test if umlauts works correctly.""" """Test if umlauts works correctly."""
self.editor.edit("Hällö Wörld") self.editor.edit("Hällö Wörld")
self.assertEqual(self._read(), "Hällö Wörld") self.assertEqual(self._read(), "Hällö Wörld")
@ -191,7 +184,7 @@ class TextModifyTests(unittest.TestCase):
self.editor.on_proc_closed(0, QProcess.NormalExit) self.editor.on_proc_closed(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("Überprüfung") self.editor.editing_finished.emit.assert_called_with("Überprüfung")
def test_unicode(self): def test_unicode(self, _proc_mock):
"""Test if other UTF8 chars work correctly.""" """Test if other UTF8 chars work correctly."""
self.editor.edit("\u2603") # Unicode snowman self.editor.edit("\u2603") # Unicode snowman
self.assertEqual(self._read(), "\u2603") self.assertEqual(self._read(), "\u2603")
@ -200,6 +193,9 @@ class TextModifyTests(unittest.TestCase):
self.editor.editing_finished.emit.assert_called_with("\u2601") 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', autospec=True)
class ErrorMessageTests(unittest.TestCase): class ErrorMessageTests(unittest.TestCase):
"""Test if statusbar error messages get emitted correctly. """Test if statusbar error messages get emitted correctly.
@ -215,17 +211,17 @@ class ErrorMessageTests(unittest.TestCase):
editor.config = stubs.ConfigStub( editor.config = stubs.ConfigStub(
{'general': {'editor': [''], 'editor-encoding': 'utf-8'}}) {'general': {'editor': [''], 'editor-encoding': 'utf-8'}})
def test_proc_error(self): def test_proc_error(self, msg_mock, _proc_mock):
"""Test on_proc_error.""" """Test on_proc_error."""
self.editor.edit("") self.editor.edit("")
self.editor.on_proc_error(QProcess.Crashed) self.editor.on_proc_error(QProcess.Crashed)
self.assertTrue(editor.message.error.called) self.assertTrue(msg_mock.error.called)
def test_proc_return(self): def test_proc_return(self, msg_mock, _proc_mock):
"""Test on_proc_finished with a bad exit status.""" """Test on_proc_finished with a bad exit status."""
self.editor.edit("") self.editor.edit("")
self.editor.on_proc_closed(1, QProcess.NormalExit) self.editor.on_proc_closed(1, QProcess.NormalExit)
self.assertTrue(editor.message.error.called) self.assertTrue(msg_mock.error.called)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -27,6 +27,7 @@ from PyQt5.QtCore import QPoint, QProcess
from PyQt5.QtNetwork import QNetworkRequest from PyQt5.QtNetwork import QNetworkRequest
from qutebrowser.config import configexc from qutebrowser.config import configexc
from qutebrowser.utils import usertypes
class ConfigStub: class ConfigStub:
@ -178,11 +179,11 @@ class FakeNetworkReply:
self.headers[key] = value self.headers[key] = value
class FakeQProcess: class FakeQProcess(mock.Mock):
"""QProcess stub. """QProcess stub.
Gets some enum values from the real QProcess and uses mocks for signals. Gets some enum values from the real QProcess.
""" """
NormalExit = QProcess.NormalExit NormalExit = QProcess.NormalExit
@ -195,11 +196,6 @@ class FakeQProcess:
ReadError = QProcess.ReadError ReadError = QProcess.ReadError
UnknownError = QProcess.UnknownError UnknownError = QProcess.UnknownError
def __init__(self, parent=None): # pylint: disable=unused-argument
self.finished = mock.Mock()
self.error = mock.Mock()
self.start = mock.Mock()
class FakeSignal: class FakeSignal:
@ -223,3 +219,12 @@ class FakeCommand:
def __init__(self, desc): def __init__(self, desc):
self.desc = desc self.desc = desc
class FakeTimer(usertypes.Timer):
"""Stub for a usertypes.Timer."""
def __init__(self, parent=None, name=None):
super().__init__(parent, name)
self.blockSignals(True)