tests: Improve MessageMock and use it.
This commit is contained in:
parent
6d1b0ba260
commit
e4a0f1972f
@ -47,12 +47,12 @@ class GUIProcess(QObject):
|
||||
Args:
|
||||
cmd: The command which was started.
|
||||
args: A list of arguments which gets passed.
|
||||
verbose: Whether to show more messages.
|
||||
_started: Whether the underlying process is started.
|
||||
_proc: The underlying QProcess.
|
||||
_win_id: The window ID this process is used in.
|
||||
_what: What kind of thing is spawned (process/editor/userscript/...).
|
||||
Used in messages.
|
||||
_verbose: Whether to show more messages.
|
||||
|
||||
Signals:
|
||||
error/finished/started signals proxied from QProcess.
|
||||
@ -67,7 +67,7 @@ class GUIProcess(QObject):
|
||||
super().__init__(parent)
|
||||
self._win_id = win_id
|
||||
self._what = what
|
||||
self._verbose = verbose
|
||||
self.verbose = verbose
|
||||
self._started = False
|
||||
self.cmd = None
|
||||
self.args = None
|
||||
@ -104,7 +104,7 @@ class GUIProcess(QObject):
|
||||
"{} crashed!".format(self._what.capitalize()),
|
||||
immediately=True)
|
||||
elif status == QProcess.NormalExit and code == 0:
|
||||
if self._verbose:
|
||||
if self.verbose:
|
||||
message.info(self._win_id, "{} exited successfully.".format(
|
||||
self._what.capitalize()))
|
||||
else:
|
||||
@ -125,7 +125,7 @@ class GUIProcess(QObject):
|
||||
raise ValueError("Trying to start a running QProcess!")
|
||||
self.cmd = cmd
|
||||
self.args = args
|
||||
if self._verbose:
|
||||
if self.verbose:
|
||||
fake_cmdline = ' '.join(shlex.quote(e) for e in [cmd] + list(args))
|
||||
message.info(self._win_id, 'Executing: ' + fake_cmdline)
|
||||
|
||||
|
@ -19,43 +19,58 @@
|
||||
|
||||
"""pytest helper to monkeypatch the message module."""
|
||||
|
||||
import pytest
|
||||
|
||||
import logging
|
||||
import collections
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser.utils import usertypes
|
||||
|
||||
|
||||
Message = collections.namedtuple('Message', ['level', 'win_id', 'text',
|
||||
'immediate'])
|
||||
|
||||
|
||||
Level = usertypes.enum('Level', ('error', 'info', 'warning'))
|
||||
|
||||
|
||||
class MessageMock:
|
||||
|
||||
"""Helper object for message_mock.
|
||||
|
||||
Attributes:
|
||||
_monkeypatch: The pytest monkeypatch fixture.
|
||||
MessageLevel: An enum with possible message levels.
|
||||
Message: A namedtuple representing a message.
|
||||
messages: A list of Message tuples.
|
||||
caplog: The pytest-capturelog fixture.
|
||||
"""
|
||||
|
||||
Message = collections.namedtuple('Message', ['level', 'win_id', 'text',
|
||||
'immediate'])
|
||||
MessageLevel = usertypes.enum('Level', ('error', 'info', 'warning'))
|
||||
|
||||
def __init__(self, monkeypatch):
|
||||
def __init__(self, monkeypatch, caplog):
|
||||
self._monkeypatch = monkeypatch
|
||||
self._caplog = caplog
|
||||
self.messages = []
|
||||
|
||||
def _handle(self, level, win_id, text, immediately=False):
|
||||
self.messages.append(self.Message(level, win_id, text, immediately))
|
||||
log_levels = {
|
||||
Level.error: logging.ERROR,
|
||||
Level.info: logging.INFO,
|
||||
Level.warning: logging.WARNING
|
||||
}
|
||||
log_level = log_levels[level]
|
||||
|
||||
with self._caplog.atLevel(log_level): # needed so we don't fail
|
||||
logging.getLogger('message').log(log_level, text)
|
||||
|
||||
self.messages.append(Message(level, win_id, text, immediately))
|
||||
|
||||
def _handle_error(self, *args, **kwargs):
|
||||
self._handle(self.MessageLevel.error, *args, **kwargs)
|
||||
self._handle(Level.error, *args, **kwargs)
|
||||
|
||||
def _handle_info(self, *args, **kwargs):
|
||||
self._handle(self.MessageLevel.info, *args, **kwargs)
|
||||
self._handle(Level.info, *args, **kwargs)
|
||||
|
||||
def _handle_warning(self, *args, **kwargs):
|
||||
self._handle(self.MessageLevel.warning, *args, **kwargs)
|
||||
self._handle(Level.warning, *args, **kwargs)
|
||||
|
||||
def getmsg(self):
|
||||
"""Get the only message in self.messages.
|
||||
@ -76,6 +91,6 @@ class MessageMock:
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def message_mock(monkeypatch):
|
||||
def message_mock(monkeypatch, caplog):
|
||||
"""Fixture to get a MessageMock."""
|
||||
return MessageMock(monkeypatch)
|
||||
return MessageMock(monkeypatch, caplog)
|
||||
|
@ -21,8 +21,6 @@
|
||||
|
||||
"""Fake objects/stubs."""
|
||||
|
||||
import logging
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QPoint, QProcess, QObject
|
||||
@ -276,25 +274,6 @@ class FakeTimer(QObject):
|
||||
return self._started
|
||||
|
||||
|
||||
class MessageModule:
|
||||
|
||||
"""A drop-in replacement for qutebrowser.utils.message."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class ConfigStub:
|
||||
|
||||
"""Stub for the config module.
|
||||
|
@ -96,9 +96,8 @@ class TestFileHandling:
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self, monkeypatch, stubs, config_stub):
|
||||
monkeypatch.setattr('qutebrowser.misc.editor.message',
|
||||
stubs.MessageModule())
|
||||
def setup(self, monkeypatch, stubs, config_stub, message_mock):
|
||||
message_mock.patch('qutebrowser.misc.editor.message')
|
||||
monkeypatch.setattr('qutebrowser.misc.editor.guiprocess.QProcess',
|
||||
stubs.fake_qprocess())
|
||||
config_stub.data = {'general': {'editor': [''],
|
||||
@ -217,11 +216,10 @@ class TestErrorMessage:
|
||||
"""
|
||||
|
||||
@pytest.yield_fixture(autouse=True)
|
||||
def setup(self, monkeypatch, stubs, config_stub):
|
||||
def setup(self, monkeypatch, stubs, config_stub, message_mock):
|
||||
monkeypatch.setattr('qutebrowser.misc.editor.guiprocess.QProcess',
|
||||
stubs.fake_qprocess())
|
||||
monkeypatch.setattr('qutebrowser.misc.editor.message',
|
||||
stubs.MessageModule())
|
||||
message_mock.patch('qutebrowser.misc.editor.message')
|
||||
config_stub.data = {'general': {'editor': [''],
|
||||
'editor-encoding': 'utf-8'}}
|
||||
monkeypatch.setattr('qutebrowser.misc.editor.config', config_stub)
|
||||
|
@ -27,6 +27,7 @@ import logging
|
||||
import pytest
|
||||
from PyQt5.QtCore import QProcess
|
||||
|
||||
from helpers import messagemock # pylint: disable=import-error
|
||||
from qutebrowser.misc import guiprocess
|
||||
|
||||
|
||||
@ -39,9 +40,9 @@ def _py_proc(code):
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_modules(monkeypatch, stubs):
|
||||
monkeypatch.setattr('qutebrowser.misc.guiprocess.message',
|
||||
stubs.MessageModule())
|
||||
def guiprocess_message_mock(message_mock):
|
||||
message_mock.patch('qutebrowser.misc.guiprocess.message')
|
||||
return message_mock
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
@ -68,13 +69,32 @@ def fake_proc(monkeypatch, stubs):
|
||||
|
||||
|
||||
@pytest.mark.not_frozen
|
||||
def test_start(proc, qtbot):
|
||||
def test_start(proc, qtbot, guiprocess_message_mock):
|
||||
"""Test simply starting a process."""
|
||||
with qtbot.waitSignals([proc.started, proc.finished], raising=True,
|
||||
timeout=10000):
|
||||
argv = _py_proc("import sys; print('test'); sys.exit(0)")
|
||||
proc.start(*argv)
|
||||
|
||||
assert not guiprocess_message_mock.messages
|
||||
assert bytes(proc._proc.readAll()).rstrip() == b'test'
|
||||
|
||||
|
||||
@pytest.mark.not_frozen
|
||||
def test_start_verbose(proc, qtbot, guiprocess_message_mock):
|
||||
"""Test starting a process verbosely."""
|
||||
proc.verbose = True
|
||||
|
||||
with qtbot.waitSignals([proc.started, proc.finished], raising=True,
|
||||
timeout=10000):
|
||||
argv = _py_proc("import sys; print('test'); sys.exit(0)")
|
||||
proc.start(*argv)
|
||||
|
||||
msgs = guiprocess_message_mock.messages
|
||||
assert msgs[0].level == messagemock.Level.info
|
||||
assert msgs[1].level == messagemock.Level.info
|
||||
assert msgs[0].text.startswith("Executing:")
|
||||
assert msgs[1].text == "Test exited successfully."
|
||||
assert bytes(proc._proc.readAll()).rstrip() == b'test'
|
||||
|
||||
|
||||
@ -120,14 +140,23 @@ def test_cmd_args(fake_proc):
|
||||
assert (fake_proc.cmd, fake_proc.args) == (cmd, args)
|
||||
|
||||
|
||||
def test_error(qtbot, proc, caplog):
|
||||
def test_error(qtbot, proc, caplog, guiprocess_message_mock):
|
||||
"""Test the process emitting an error."""
|
||||
with caplog.atLevel(logging.ERROR, 'message'):
|
||||
with qtbot.waitSignal(proc.error, raising=True):
|
||||
proc.start('this_does_not_exist_either', [])
|
||||
|
||||
msg = guiprocess_message_mock.getmsg()
|
||||
assert msg.level == messagemock.Level.error
|
||||
expected_msg = "Error while spawning test: The process failed to start."
|
||||
assert msg.text == expected_msg
|
||||
|
||||
|
||||
@pytest.mark.not_frozen
|
||||
def test_exit_unsuccessful(qtbot, proc):
|
||||
def test_exit_unsuccessful(qtbot, proc, guiprocess_message_mock):
|
||||
with qtbot.waitSignal(proc.finished, raising=True, timeout=10000):
|
||||
proc.start(*_py_proc('import sys; sys.exit(0)'))
|
||||
proc.start(*_py_proc('import sys; sys.exit(1)'))
|
||||
|
||||
msg = guiprocess_message_mock.getmsg()
|
||||
assert msg.level == messagemock.Level.error
|
||||
assert msg.text == "Test exited with status 1."
|
||||
|
Loading…
Reference in New Issue
Block a user