diff --git a/tests/helpers/messagemock.py b/tests/helpers/messagemock.py index 531586cab..6927f7b8b 100644 --- a/tests/helpers/messagemock.py +++ b/tests/helpers/messagemock.py @@ -23,15 +23,12 @@ import logging import collections import pytest +from PyQt5.QtCore import pyqtSlot -from qutebrowser.utils import usertypes +from qutebrowser.utils import usertypes, message -Message = collections.namedtuple('Message', ['level', 'win_id', 'text', - 'immediate']) - - -Level = usertypes.enum('Level', ('error', 'info', 'warning')) +Message = collections.namedtuple('Message', ['level', 'text']) class MessageMock: @@ -39,70 +36,53 @@ class MessageMock: """Helper object for message_mock. Attributes: - _monkeypatch: The pytest monkeypatch fixture. Message: A namedtuple representing a message. messages: A list of Message tuples. - caplog: The pytest-capturelog fixture. - Level: The Level type for easier usage as a fixture. """ - Level = Level - - def __init__(self, monkeypatch, caplog): - self._monkeypatch = monkeypatch - self._caplog = caplog + def __init__(self): self.messages = [] - def _handle(self, level, win_id, text, immediately=False, *, - stack=None): # pylint: disable=unused-variable + @pyqtSlot(usertypes.MessageLevel, str) + def _record_message(self, level, text): log_levels = { - Level.error: logging.ERROR, - Level.info: logging.INFO, - Level.warning: logging.WARNING + usertypes.MessageLevel.error: logging.ERROR, + usertypes.MessageLevel.info: logging.INFO, + usertypes.MessageLevel.warning: logging.WARNING, } log_level = log_levels[level] logging.getLogger('messagemock').log(log_level, text) - self.messages.append(Message(level, win_id, text, immediately)) + self.messages.append(Message(level, text)) - def _handle_error(self, *args, **kwargs): - self._handle(Level.error, *args, **kwargs) - - def _handle_info(self, *args, **kwargs): - self._handle(Level.info, *args, **kwargs) - - def _handle_warning(self, *args, **kwargs): - self._handle(Level.warning, *args, **kwargs) - - def getmsg(self, level=None, *, win_id=0, immediate=False): + def getmsg(self, level=None): """Get the only message in self.messages. Raises ValueError if there are multiple or no messages. Args: level: The message level to check against, or None. - win_id: The window id to check against. - immediate: If the message has the immediate flag set. """ assert len(self.messages) == 1 msg = self.messages[0] - if level is not None: assert msg.level == level - assert msg.win_id == win_id - assert msg.immediate == immediate - return msg - def patch(self, module_path): - """Patch message.* in the given module (as a string).""" - self._monkeypatch.setattr(module_path + '.error', self._handle_error) - self._monkeypatch.setattr(module_path + '.info', self._handle_info) - self._monkeypatch.setattr(module_path + '.warning', - self._handle_warning) + def patch(self): + """Start recording messages.""" + message.global_bridge.show_message.connect(self._record_message) + + def unpatch(self): + """Stop recording messages.""" + message.global_bridge.show_message.disconnect(self._record_message) @pytest.fixture -def message_mock(monkeypatch, caplog): +def message_mock(): """Fixture to get a MessageMock.""" - return MessageMock(monkeypatch, caplog) + message.init() + mmock = MessageMock() + mmock.patch() + yield mmock + mmock.unpatch() diff --git a/tests/unit/browser/test_adblock.py b/tests/unit/browser/test_adblock.py index 03b114889..5c33b1141 100644 --- a/tests/unit/browser/test_adblock.py +++ b/tests/unit/browser/test_adblock.py @@ -68,13 +68,6 @@ def basedir(fake_args): fake_args.basedir = None -@pytest.fixture -def adblock_message_mock(message_mock): - """Customized message_mock for the adblock module.""" - message_mock.patch('qutebrowser.browser.adblock.message') - return message_mock - - class FakeDownloadItem(QObject): """Mock browser.downloads.DownloadItem.""" @@ -257,8 +250,7 @@ def test_without_datadir(config_stub, tmpdir, monkeypatch, win_registry): def test_disabled_blocking_update(basedir, config_stub, download_stub, - data_tmpdir, tmpdir, win_registry, - adblock_message_mock): + data_tmpdir, tmpdir, win_registry): """Ensure no URL is blocked when host blocking is disabled.""" config_stub.data = { 'content': { @@ -293,8 +285,7 @@ def test_no_blocklist_update(config_stub, download_stub, def test_successful_update(config_stub, basedir, download_stub, - data_tmpdir, tmpdir, win_registry, - adblock_message_mock): + data_tmpdir, tmpdir, win_registry): """Ensure hosts from host-block-lists are blocked after an update.""" config_stub.data = { 'content': { @@ -314,8 +305,7 @@ def test_successful_update(config_stub, basedir, download_stub, def test_failed_dl_update(config_stub, basedir, download_stub, - data_tmpdir, tmpdir, win_registry, - adblock_message_mock): + data_tmpdir, tmpdir, win_registry): """One blocklist fails to download. Ensure hosts from this list are not blocked. diff --git a/tests/unit/commands/test_userscripts.py b/tests/unit/commands/test_userscripts.py index 69445ee91..9bb0d60cd 100644 --- a/tests/unit/commands/test_userscripts.py +++ b/tests/unit/commands/test_userscripts.py @@ -29,12 +29,6 @@ from PyQt5.QtCore import QFileSystemWatcher from qutebrowser.commands import userscripts -@pytest.fixture(autouse=True) -def guiprocess_message_mock(message_mock): - message_mock.patch('qutebrowser.misc.guiprocess.message') - return message_mock - - @pytest.mark.posix class TestQtFIFOReader: diff --git a/tests/unit/misc/test_editor.py b/tests/unit/misc/test_editor.py index 8bb07698e..4dabb7efb 100644 --- a/tests/unit/misc/test_editor.py +++ b/tests/unit/misc/test_editor.py @@ -30,8 +30,7 @@ from qutebrowser.misc import editor as editormod @pytest.fixture(autouse=True) -def patch_things(config_stub, message_mock, monkeypatch, stubs): - message_mock.patch('qutebrowser.misc.editor.message') +def patch_things(config_stub, monkeypatch, stubs): monkeypatch.setattr('qutebrowser.misc.editor.guiprocess.QProcess', stubs.fake_qprocess()) config_stub.data = { @@ -130,7 +129,7 @@ class TestFileHandling: os.chmod(filename, 0o077) editor._proc.finished.emit(0, QProcess.NormalExit) assert not os.path.exists(filename) - msg = message_mock.getmsg(message_mock.Level.error) + msg = message_mock.getmsg(usertypes.MessageLevel.error) assert msg.text.startswith("Failed to read back edited file: ") @pytest.mark.posix @@ -140,7 +139,7 @@ class TestFileHandling: monkeypatch.setattr('qutebrowser.misc.editor.tempfile.tempdir', str(tmpdir)) editor.edit("") - msg = message_mock.getmsg(message_mock.Level.error) + msg = message_mock.getmsg(usertypes.MessageLevel.error) assert msg.text.startswith("Failed to create initial file: ") assert editor._proc is None diff --git a/tests/unit/misc/test_guiprocess.py b/tests/unit/misc/test_guiprocess.py index a706accb5..e78d12bf0 100644 --- a/tests/unit/misc/test_guiprocess.py +++ b/tests/unit/misc/test_guiprocess.py @@ -28,12 +28,6 @@ from PyQt5.QtCore import QProcess, QIODevice from qutebrowser.misc import guiprocess -@pytest.fixture(autouse=True) -def guiprocess_message_mock(message_mock): - message_mock.patch('qutebrowser.misc.guiprocess.message') - return message_mock - - @pytest.fixture() def proc(qtbot): """A fixture providing a GUIProcess and cleaning it up after the test.""" @@ -55,18 +49,18 @@ def fake_proc(monkeypatch, stubs): return p -def test_start(proc, qtbot, guiprocess_message_mock, py_proc): +def test_start(proc, qtbot, message_mock, py_proc): """Test simply starting a process.""" with qtbot.waitSignals([proc.started, proc.finished], timeout=10000, order='strict'): argv = py_proc("import sys; print('test'); sys.exit(0)") proc.start(*argv) - assert not guiprocess_message_mock.messages + assert not message_mock.messages assert bytes(proc._proc.readAll()).rstrip() == b'test' -def test_start_verbose(proc, qtbot, guiprocess_message_mock, py_proc): +def test_start_verbose(proc, qtbot, message_mock, py_proc): """Test starting a process verbosely.""" proc.verbose = True @@ -75,9 +69,9 @@ def test_start_verbose(proc, qtbot, guiprocess_message_mock, py_proc): argv = py_proc("import sys; print('test'); sys.exit(0)") proc.start(*argv) - msgs = guiprocess_message_mock.messages - assert msgs[0].level == guiprocess_message_mock.Level.info - assert msgs[1].level == guiprocess_message_mock.Level.info + msgs = message_mock.messages + assert msgs[0].level == usertypes.MessageLevel.info + assert msgs[1].level == usertypes.MessageLevel.info assert msgs[0].text.startswith("Executing:") assert msgs[1].text == "Testprocess exited successfully." assert bytes(proc._proc.readAll()).rstrip() == b'test' @@ -127,14 +121,13 @@ def test_start_detached(fake_proc): fake_proc._proc.startDetached.assert_called_with(*list(argv) + [None]) -def test_start_detached_error(fake_proc, guiprocess_message_mock): +def test_start_detached_error(fake_proc, message_mock): """Test starting a detached process with ok=False.""" argv = ['foo', 'bar'] fake_proc._proc.startDetached.return_value = (False, 0) fake_proc._proc.error.return_value = "Error message" fake_proc.start_detached(*argv) - msg = guiprocess_message_mock.getmsg(guiprocess_message_mock.Level.error, - immediate=True) + msg = message_mock.getmsg(usertypes.MessageLevel.error) assert msg.text == "Error while spawning testprocess: Error message." @@ -178,24 +171,23 @@ def test_start_logging(fake_proc, caplog): "Executing: does_not_exist arg 'arg with spaces'"] -def test_error(qtbot, proc, caplog, guiprocess_message_mock): +def test_error(qtbot, proc, caplog, message_mock): """Test the process emitting an error.""" with caplog.at_level(logging.ERROR, 'message'): with qtbot.waitSignal(proc.error, timeout=5000): proc.start('this_does_not_exist_either', []) - msg = guiprocess_message_mock.getmsg(guiprocess_message_mock.Level.error, - immediate=True) + msg = message_mock.getmsg(usertypes.MessageLevel.error) expected_msg = ("Error while spawning testprocess: The process failed to " "start.") assert msg.text == expected_msg -def test_exit_unsuccessful(qtbot, proc, guiprocess_message_mock, py_proc): +def test_exit_unsuccessful(qtbot, proc, message_mock, py_proc): with qtbot.waitSignal(proc.finished, timeout=10000): proc.start(*py_proc('import sys; sys.exit(1)')) - msg = guiprocess_message_mock.getmsg(guiprocess_message_mock.Level.error) + msg = message_mock.getmsg(usertypes.MessageLevel.error) assert msg.text == "Testprocess exited with status 1." diff --git a/tests/unit/utils/test_urlutils.py b/tests/unit/utils/test_urlutils.py index 3515696d0..8e62a1b5b 100644 --- a/tests/unit/utils/test_urlutils.py +++ b/tests/unit/utils/test_urlutils.py @@ -26,7 +26,7 @@ from PyQt5.QtCore import QUrl import pytest from qutebrowser.commands import cmdexc -from qutebrowser.utils import utils, urlutils, qtutils +from qutebrowser.utils import utils, urlutils, qtutils, usertypes class FakeDNS: @@ -106,13 +106,6 @@ def urlutils_config_stub(config_stub, monkeypatch): return config_stub -@pytest.fixture -def urlutils_message_mock(message_mock): - """Customized message_mock for the urlutils module.""" - message_mock.patch('qutebrowser.utils.urlutils.message') - return message_mock - - class TestFuzzyUrl: """Tests for urlutils.fuzzy_url().""" @@ -419,7 +412,7 @@ def test_qurl_from_user_input(user_input, output): ('', False, False), ('://', False, True), ]) -def test_invalid_url_error(urlutils_message_mock, url, valid, has_err_string): +def test_invalid_url_error(message_mock, url, valid, has_err_string): """Test invalid_url_error(). Args: @@ -432,12 +425,12 @@ def test_invalid_url_error(urlutils_message_mock, url, valid, has_err_string): if valid: with pytest.raises(ValueError): urlutils.invalid_url_error(qurl, '') - assert not urlutils_message_mock.messages + assert not message_mock.messages else: assert bool(qurl.errorString()) == has_err_string urlutils.invalid_url_error(qurl, 'frozzle') - msg = urlutils_message_mock.getmsg(urlutils_message_mock.Level.error) + msg = message_mock.getmsg(usertypes.MessageLevel.error) if has_err_string: expected_text = ("Trying to frozzle with invalid URL - " + qurl.errorString())