490250f5be
test_selectors and test_get_all_objects were running fine on my machine, but for some reason is failing with "Driver not loaded" on Travis. Let's try initializing SQL and see what happens.
279 lines
8.6 KiB
Python
279 lines
8.6 KiB
Python
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
|
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
|
|
|
#
|
|
# 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.debug."""
|
|
|
|
import logging
|
|
import re
|
|
import time
|
|
import textwrap
|
|
|
|
import pytest
|
|
from PyQt5.QtCore import pyqtSignal, Qt, QEvent, QObject
|
|
from PyQt5.QtWidgets import QStyle, QFrame
|
|
|
|
from qutebrowser.utils import debug
|
|
|
|
|
|
@debug.log_events
|
|
class EventObject(QObject):
|
|
|
|
pass
|
|
|
|
|
|
def test_log_events(qapp, caplog):
|
|
obj = EventObject()
|
|
qapp.sendEvent(obj, QEvent(QEvent.User))
|
|
qapp.processEvents()
|
|
assert len(caplog.records) == 1
|
|
assert caplog.records[0].msg == 'Event in test_debug.EventObject: User'
|
|
|
|
|
|
class SignalObject(QObject):
|
|
|
|
signal1 = pyqtSignal()
|
|
signal2 = pyqtSignal(str, str)
|
|
|
|
def __repr__(self):
|
|
"""This is not a nice thing to do, but it makes our tests easier."""
|
|
return '<repr>'
|
|
|
|
|
|
@debug.log_signals
|
|
class DecoratedSignalObject(SignalObject):
|
|
|
|
pass
|
|
|
|
|
|
@pytest.fixture(params=[(SignalObject, True), (DecoratedSignalObject, False)])
|
|
def signal_obj(request):
|
|
klass, wrap = request.param
|
|
obj = klass()
|
|
if wrap:
|
|
debug.log_signals(obj)
|
|
return obj
|
|
|
|
|
|
def test_log_signals(caplog, signal_obj):
|
|
signal_obj.signal1.emit()
|
|
signal_obj.signal2.emit('foo', 'bar')
|
|
|
|
assert len(caplog.records) == 2
|
|
assert caplog.records[0].msg == 'Signal in <repr>: signal1()'
|
|
assert caplog.records[1].msg == "Signal in <repr>: signal2('foo', 'bar')"
|
|
|
|
|
|
class TestLogTime:
|
|
|
|
def test_duration(self, caplog):
|
|
logger_name = 'qt-tests'
|
|
|
|
with caplog.at_level(logging.DEBUG, logger_name):
|
|
with debug.log_time(logger_name, action='foobar'):
|
|
time.sleep(0.1)
|
|
|
|
assert len(caplog.records) == 1
|
|
|
|
pattern = re.compile(r'^Foobar took ([\d.]*) seconds\.$')
|
|
match = pattern.match(caplog.records[0].msg)
|
|
assert match
|
|
|
|
duration = float(match.group(1))
|
|
assert 0 < duration < 30
|
|
|
|
def test_logger(self, caplog):
|
|
"""Test with an explicit logger instead of a name."""
|
|
logger_name = 'qt-tests'
|
|
|
|
with caplog.at_level(logging.DEBUG, logger_name):
|
|
with debug.log_time(logging.getLogger(logger_name)):
|
|
pass
|
|
|
|
assert len(caplog.records) == 1
|
|
|
|
def test_decorator(self, caplog):
|
|
logger_name = 'qt-tests'
|
|
|
|
@debug.log_time(logger_name, action='foo')
|
|
def func(arg, *, kwarg):
|
|
assert arg == 1
|
|
assert kwarg == 2
|
|
|
|
with caplog.at_level(logging.DEBUG, logger_name):
|
|
func(1, kwarg=2)
|
|
|
|
assert len(caplog.records) == 1
|
|
assert caplog.records[0].msg.startswith('Foo took')
|
|
|
|
|
|
class TestQEnumKey:
|
|
|
|
def test_metaobj(self):
|
|
"""Make sure the classes we use in the tests have a metaobj or not.
|
|
|
|
If Qt/PyQt even changes and our tests wouldn't test the full
|
|
functionality of qenum_key because of that, this test will tell us.
|
|
"""
|
|
assert not hasattr(QStyle.PrimitiveElement, 'staticMetaObject')
|
|
assert hasattr(QFrame, 'staticMetaObject')
|
|
|
|
@pytest.mark.parametrize('base, value, klass, expected', [
|
|
(QStyle, QStyle.PE_PanelButtonCommand, None, 'PE_PanelButtonCommand'),
|
|
(QFrame, QFrame.Sunken, None, 'Sunken'),
|
|
(QFrame, 0x0030, QFrame.Shadow, 'Sunken'),
|
|
(QFrame, 0x1337, QFrame.Shadow, '0x1337'),
|
|
(Qt, Qt.AnchorLeft, None, 'AnchorLeft'),
|
|
])
|
|
def test_qenum_key(self, base, value, klass, expected):
|
|
key = debug.qenum_key(base, value, klass=klass)
|
|
assert key == expected
|
|
|
|
def test_add_base(self):
|
|
key = debug.qenum_key(QFrame, QFrame.Sunken, add_base=True)
|
|
assert key == 'QFrame.Sunken'
|
|
|
|
def test_int_noklass(self):
|
|
"""Test passing an int without explicit klass given."""
|
|
with pytest.raises(TypeError):
|
|
debug.qenum_key(QFrame, 42)
|
|
|
|
|
|
class TestQFlagsKey:
|
|
|
|
"""Tests for qutebrowser.utils.debug.qflags_key.
|
|
|
|
https://github.com/qutebrowser/qutebrowser/issues/42
|
|
"""
|
|
|
|
fixme = pytest.mark.xfail(reason="See issue #42", raises=AssertionError)
|
|
|
|
@pytest.mark.parametrize('base, value, klass, expected', [
|
|
(Qt, Qt.AlignTop, None, 'AlignTop'),
|
|
pytest.param(Qt, Qt.AlignLeft | Qt.AlignTop, None,
|
|
'AlignLeft|AlignTop', marks=fixme),
|
|
(Qt, Qt.AlignCenter, None, 'AlignHCenter|AlignVCenter'),
|
|
pytest.param(Qt, 0x0021, Qt.Alignment, 'AlignLeft|AlignTop',
|
|
marks=fixme),
|
|
(Qt, 0x1100, Qt.Alignment, '0x0100|0x1000'),
|
|
(Qt, Qt.DockWidgetAreas(0), Qt.DockWidgetArea, 'NoDockWidgetArea'),
|
|
(Qt, Qt.DockWidgetAreas(0), None, '0x0000'),
|
|
])
|
|
def test_qflags_key(self, base, value, klass, expected):
|
|
flags = debug.qflags_key(base, value, klass=klass)
|
|
assert flags == expected
|
|
|
|
def test_add_base(self):
|
|
"""Test with add_base=True."""
|
|
flags = debug.qflags_key(Qt, Qt.AlignTop, add_base=True)
|
|
assert flags == 'Qt.AlignTop'
|
|
|
|
def test_int_noklass(self):
|
|
"""Test passing an int without explicit klass given."""
|
|
with pytest.raises(TypeError):
|
|
debug.qflags_key(Qt, 42)
|
|
|
|
|
|
@pytest.mark.parametrize('signal, expected', [
|
|
(SignalObject().signal1, 'signal1'),
|
|
(SignalObject().signal2, 'signal2'),
|
|
])
|
|
def test_signal_name(signal, expected):
|
|
assert debug.signal_name(signal) == expected
|
|
|
|
|
|
@pytest.mark.parametrize('args, kwargs, expected', [
|
|
([], {}, ''),
|
|
(None, None, ''),
|
|
(['foo'], None, "'foo'"),
|
|
(['foo', 'bar'], None, "'foo', 'bar'"),
|
|
(None, {'foo': 'bar'}, "foo='bar'"),
|
|
(['foo', 'bar'], {'baz': 'fish'}, "'foo', 'bar', baz='fish'"),
|
|
(['x' * 300], None, "'{}".format('x' * 198 + '…')),
|
|
], ids=lambda val: str(val)[:20])
|
|
def test_format_args(args, kwargs, expected):
|
|
assert debug.format_args(args, kwargs) == expected
|
|
|
|
|
|
def func():
|
|
pass
|
|
|
|
|
|
@pytest.mark.parametrize('func, args, kwargs, full, expected', [
|
|
(func, None, None, False, 'func()'),
|
|
(func, [1, 2], None, False, 'func(1, 2)'),
|
|
(func, [1, 2], None, True, 'test_debug.func(1, 2)'),
|
|
(func, [1, 2], {'foo': 3}, False, 'func(1, 2, foo=3)'),
|
|
])
|
|
def test_format_call(func, args, kwargs, full, expected):
|
|
assert debug.format_call(func, args, kwargs, full) == expected
|
|
|
|
|
|
@pytest.mark.parametrize('args, expected', [
|
|
([23, 42], 'fake(23, 42)'),
|
|
(['x' * 201], "fake('{}\u2026)".format('x' * 198)),
|
|
(['foo\nbar'], r"fake('foo\nbar')"),
|
|
], ids=lambda val: str(val)[:20])
|
|
def test_dbg_signal(stubs, args, expected):
|
|
assert debug.dbg_signal(stubs.FakeSignal(), args) == expected
|
|
|
|
|
|
class TestGetAllObjects:
|
|
|
|
class Object(QObject):
|
|
|
|
def __init__(self, name, parent=None):
|
|
self._name = name
|
|
super().__init__(parent)
|
|
|
|
def __repr__(self):
|
|
return '<{}>'.format(self._name)
|
|
|
|
def test_get_all_objects(self, stubs, monkeypatch, init_sql):
|
|
# pylint: disable=unused-variable
|
|
widgets = [self.Object('Widget 1'), self.Object('Widget 2')]
|
|
app = stubs.FakeQApplication(all_widgets=widgets)
|
|
monkeypatch.setattr(debug, 'QApplication', app)
|
|
|
|
root = QObject()
|
|
o1 = self.Object('Object 1', root)
|
|
o2 = self.Object('Object 2', o1) # flake8: disable=F841
|
|
o3 = self.Object('Object 3', root) # flake8: disable=F841
|
|
|
|
expected = textwrap.dedent("""
|
|
Qt widgets - 2 objects:
|
|
<Widget 1>
|
|
<Widget 2>
|
|
|
|
Qt objects - 3 objects:
|
|
<Object 1>
|
|
<Object 2>
|
|
<Object 3>
|
|
|
|
global object registry - 0 objects:
|
|
""").rstrip('\n')
|
|
|
|
assert debug.get_all_objects(start_obj=root) == expected
|
|
|
|
@pytest.mark.usefixtures('qapp')
|
|
def test_get_all_objects_qapp(self):
|
|
objects = debug.get_all_objects()
|
|
event_dispatcher = '<PyQt5.QtCore.QAbstractEventDispatcher object at'
|
|
session_manager = '<PyQt5.QtGui.QSessionManager object at'
|
|
assert event_dispatcher in objects or session_manager in objects
|