tests: Use pytest.param

This commit is contained in:
Florian Bruhin 2017-05-23 08:08:46 +02:00
parent 18a761369b
commit af7923de4d
12 changed files with 165 additions and 145 deletions

View File

@ -147,8 +147,7 @@ def test_quteprocess_quitting(qtbot, quteproc_process):
@pytest.mark.parametrize('data, attrs', [
(
# Normal message
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "DEBUG", "name": "init", '
'"module": "earlyinit", "funcName": "init_log", "lineno": 280, '
'"levelno": 10, "message": "Log initialized."}',
@ -161,31 +160,31 @@ def test_quteprocess_quitting(qtbot, quteproc_process):
'line': 280,
'message': 'Log initialized.',
'expected': False,
}
),
(
# VDEBUG
},
id='normal'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "VDEBUG", "name": "foo", '
'"module": "foo", "funcName": "foo", "lineno": 0, "levelno": 9, '
'"message": ""}',
{'loglevel': log.VDEBUG_LEVEL}
),
(
# Unknown module
{'loglevel': log.VDEBUG_LEVEL},
id='vdebug'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "DEBUG", "name": "qt", '
'"module": null, "funcName": null, "lineno": 0, "levelno": 10, '
'"message": "test"}',
{'module': None, 'function': None, 'line': None},
),
(
# Expected message
id='unknown module'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "VDEBUG", "name": "foo", '
'"module": "foo", "funcName": "foo", "lineno": 0, "levelno": 9, '
'"message": "SpellCheck: test"}',
{'expected': True},
),
(
# Weird Qt location
id='expected message'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "DEBUG", "name": "qt", '
'"module": "qnetworkreplyhttpimpl", "funcName": '
'"void QNetworkReplyHttpImplPrivate::error('
@ -197,9 +196,10 @@ def test_quteprocess_quitting(qtbot, quteproc_process):
'function': 'void QNetworkReplyHttpImplPrivate::error('
'QNetworkReply::NetworkError, const QString&)',
'line': 1929
}
),
(
},
id='weird Qt location'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "DEBUG", "name": "qt", '
'"module": "qxcbxsettings", "funcName": "QXcbXSettings::QXcbXSettings('
'QXcbScreen*)", "lineno": 233, "levelno": 10, "message": '
@ -209,19 +209,18 @@ def test_quteprocess_quitting(qtbot, quteproc_process):
'module': 'qxcbxsettings',
'function': 'QXcbXSettings::QXcbXSettings(QXcbScreen*)',
'line': 233,
}
),
(
# ResourceWarning
},
id='QXcbXSettings'),
pytest.param(
'{"created": 86400, "msecs": 0, "levelname": "WARNING", '
'"name": "py.warnings", "module": "app", "funcName": "qt_mainloop", '
'"lineno": 121, "levelno": 30, "message": '
'".../app.py:121: ResourceWarning: unclosed file <_io.TextIOWrapper '
'name=18 mode=\'r\' encoding=\'UTF-8\'>"}',
{'category': 'py.warnings'}
),
], ids=['normal', 'vdebug', 'unknown module', 'expected message',
'weird Qt location', 'QXcbXSettings', 'resourcewarning'])
{'category': 'py.warnings'},
id='resourcewarning'),
])
def test_log_line_parse(data, attrs):
line = quteprocess.LogLine(data)
for name, expected in attrs.items():
@ -230,15 +229,15 @@ def test_log_line_parse(data, attrs):
@pytest.mark.parametrize('data, colorized, expect_error, expected', [
(
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'DEBUG', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 10,
'message': 'quux'},
False, False,
'{timestamp} DEBUG foo bar:qux:10 quux',
),
# Traceback attached
(
id='normal'),
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'DEBUG', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 10,
'message': 'quux', 'traceback': 'Traceback (most recent call '
@ -247,43 +246,42 @@ def test_log_line_parse(data, attrs):
'{timestamp} DEBUG foo bar:qux:10 quux\n'
'Traceback (most recent call last):\n'
' here be dragons',
),
# Colorized
(
id='traceback'),
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'DEBUG', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 10,
'message': 'quux'},
True, False,
'\033[32m{timestamp}\033[0m \033[37mDEBUG \033[0m \033[36mfoo '
' bar:qux:10\033[0m \033[37mquux\033[0m',
),
# Expected error
(
id='colored'),
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'ERROR', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 40,
'message': 'quux'},
False, True,
'{timestamp} ERROR (expected) foo bar:qux:10 quux',
),
# Expected other message (i.e. should make no difference)
(
id='expected error'),
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'DEBUG', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 10,
'message': 'quux'},
False, True,
'{timestamp} DEBUG foo bar:qux:10 quux',
),
# Expected error colorized (shouldn't be red)
(
id='expected other'),
pytest.param(
{'created': 86400, 'msecs': 0, 'levelname': 'ERROR', 'name': 'foo',
'module': 'bar', 'funcName': 'qux', 'lineno': 10, 'levelno': 40,
'message': 'quux'},
True, True,
'\033[32m{timestamp}\033[0m \033[37mERROR (expected)\033[0m '
'\033[36mfoo bar:qux:10\033[0m \033[37mquux\033[0m',
),
], ids=['normal', 'traceback', 'colored', 'expected error', 'expected other',
'expected error colorized'])
id='expected error colorized'),
])
def test_log_line_formatted(data, colorized, expect_error, expected):
line = json.dumps(data)
record = quteprocess.LogLine(line)

View File

@ -32,10 +32,10 @@ from helpers import utils
('foo(1)', 'foo'),
('foo(a)', 'foo(a)'),
('foo1', 'foo1'),
utils.qt58(('foo%20bar', 'foo bar')),
utils.qt58(('foo%2Fbar', 'bar')),
utils.qt59(('foo%20bar', 'foo%20bar')),
utils.qt59(('foo%2Fbar', 'foo%2Fbar')),
pytest.param('foo%20bar', 'foo bar', marks=utils.qt58),
pytest.param('foo%2Fbar', 'bar', marks=utils.qt58),
pytest.param('foo%20bar', 'foo%20bar', marks=utils.qt59),
pytest.param('foo%2Fbar', 'foo%2Fbar', marks=utils.qt59),
])
def test_get_suggested_filename(path, expected):
assert webenginedownloads._get_suggested_filename(path) == expected

View File

@ -141,8 +141,9 @@ def test_file_encoded_as_base64(checker):
""")
@pytest.mark.parametrize('transfer_encoding', [mhtml.E_BASE64, mhtml.E_QUOPRI],
ids=['base64', 'quoted-printable'])
@pytest.mark.parametrize('transfer_encoding', [
pytest.param(mhtml.E_BASE64, id='base64'),
pytest.param(mhtml.E_QUOPRI, id='quoted-printable')])
def test_payload_lines_wrap(checker, transfer_encoding):
payload = b'1234567890' * 10
writer = mhtml.MHTMLWriter(root_content=b'', content_type='text/plain',
@ -257,21 +258,26 @@ def test_empty_content_type(checker):
@pytest.mark.parametrize('has_cssutils', [
pytest.mark.skipif(cssutils is None, reason="requires cssutils")(True),
False,
], ids=['with_cssutils', 'no_cssutils'])
pytest.param(True, marks=pytest.mark.skipif(
cssutils is None, reason="requires cssutils"), id='with_cssutils'),
pytest.param(False, id='no_cssutils'),
])
@pytest.mark.parametrize('inline, style, expected_urls', [
(False, "@import 'default.css'", ['default.css']),
(False, '@import "default.css"', ['default.css']),
(False, "@import \t 'tabbed.css'", ['tabbed.css']),
(False, "@import url('default.css')", ['default.css']),
(False, """body {
pytest.param(False, "@import 'default.css'", ['default.css'],
id='import with apostrophe'),
pytest.param(False, '@import "default.css"', ['default.css'],
id='import with quote'),
pytest.param(False, "@import \t 'tabbed.css'", ['tabbed.css'],
id='import with tab'),
pytest.param(False, "@import url('default.css')", ['default.css'],
id='import with url()'),
pytest.param(False, """body {
background: url("/bg-img.png")
}""", ['/bg-img.png']),
(True, 'background: url(folder/file.png) no-repeat', ['folder/file.png']),
(True, 'content: url()', []),
], ids=['import with apostrophe', 'import with quote', 'import with tab',
'import with url()', 'background with body', 'background', 'content'])
}""", ['/bg-img.png'], id='background with body'),
pytest.param(True, 'background: url(folder/file.png) no-repeat',
['folder/file.png'], id='background'),
pytest.param(True, 'content: url()', [], id='content'),
])
def test_css_url_scanner(monkeypatch, has_cssutils, inline, style,
expected_urls):
if not has_cssutils:

View File

@ -244,32 +244,30 @@ class TestWebKitElement:
assert str(excinfo.value) == "Trying to wrap a wrapper!"
@pytest.mark.parametrize('code', [
str,
lambda e: e[None],
lambda e: operator.setitem(e, None, None),
lambda e: operator.delitem(e, None),
lambda e: None in e,
list, # __iter__
len,
lambda e: e.has_frame(),
lambda e: e.geometry(),
lambda e: e.value(),
lambda e: e.set_value('foo'),
lambda e: e.insert_text('foo'),
lambda e: e.is_writable(),
lambda e: e.is_content_editable(),
lambda e: e.is_editable(),
lambda e: e.is_text_input(),
lambda e: e.remove_blank_target(),
lambda e: e.outer_xml(),
lambda e: e.tag_name(),
lambda e: e.rect_on_view(),
lambda e: e._is_visible(None),
], ids=['str', 'getitem', 'setitem', 'delitem', 'contains', 'iter', 'len',
'frame', 'geometry', 'value', 'set_value', 'insert_text',
'is_writable', 'is_content_editable', 'is_editable',
'is_text_input', 'remove_blank_target', 'outer_xml', 'tag_name',
'rect_on_view', 'is_visible'])
pytest.param(str, id='str'),
pytest.param(lambda e: e[None], id='getitem'),
pytest.param(lambda e: operator.setitem(e, None, None), id='setitem'),
pytest.param(lambda e: operator.delitem(e, None), id='delitem'),
pytest.param(lambda e: None in e, id='contains'),
pytest.param(list, id='iter'),
pytest.param(len, id='len'),
pytest.param(lambda e: e.has_frame(), id='has_frame'),
pytest.param(lambda e: e.geometry(), id='geometry'),
pytest.param(lambda e: e.value(), id='value'),
pytest.param(lambda e: e.set_value('foo'), id='set_value'),
pytest.param(lambda e: e.insert_text('foo'), id='insert_text'),
pytest.param(lambda e: e.is_writable(), id='is_writable'),
pytest.param(lambda e: e.is_content_editable(),
id='is_content_editable'),
pytest.param(lambda e: e.is_editable(), id='is_editable'),
pytest.param(lambda e: e.is_text_input(), id='is_text_input'),
pytest.param(lambda e: e.remove_blank_target(),
id='remove_blank_target'),
pytest.param(lambda e: e.outer_xml(), id='outer_xml'),
pytest.param(lambda e: e.tag_name(), id='tag_name'),
pytest.param(lambda e: e.rect_on_view(), id='rect_on_view'),
pytest.param(lambda e: e._is_visible(None), id='is_visible'),
])
def test_vanished(self, elem, code):
"""Make sure methods check if the element is vanished."""
elem._elem.isNull.return_value = True

View File

@ -172,8 +172,8 @@ def _set_cmd_prompt(cmd, txt):
(':open | -t', usertypes.Completion.url, ''),
(':tab-detach |', None, ''),
(':bind --mode=caret <c-x> |', usertypes.Completion.command, ''),
pytest.mark.xfail(reason='issue #74')((':bind --mode caret <c-x> |',
usertypes.Completion.command, '')),
pytest.param(':bind --mode caret <c-x> |', usertypes.Completion.command,
'', marks=pytest.mark.xfail(reason='issue #74')),
(':set -t -p |', usertypes.Completion.section, ''),
(':open -- |', None, ''),
(':gibberish nonesense |', None, ''),

View File

@ -1031,16 +1031,16 @@ class TestFont:
klass(none_ok=True).validate(val)
@pytest.mark.parametrize('val', [
font_xfail('green "Foobar Neue"'),
font_xfail('italic green "Foobar Neue"'),
font_xfail('bold bold "Foobar Neue"'),
font_xfail('bold italic "Foobar Neue"'),
font_xfail('10pt 20px "Foobar Neue"'),
font_xfail('bold'),
font_xfail('italic'),
font_xfail('green'),
font_xfail('10pt'),
font_xfail('10pt ""'),
pytest.param('green "Foobar Neue"', marks=font_xfail),
pytest.param('italic green "Foobar Neue"', marks=font_xfail),
pytest.param('bold bold "Foobar Neue"', marks=font_xfail),
pytest.param('bold italic "Foobar Neue"', marks=font_xfail),
pytest.param('10pt 20px "Foobar Neue"', marks=font_xfail),
pytest.param('bold', marks=font_xfail),
pytest.param('italic', marks=font_xfail),
pytest.param('green', marks=font_xfail),
pytest.param('10pt', marks=font_xfail),
pytest.param('10pt ""', marks=font_xfail),
'',
])
def test_validate_invalid(self, klass, val):
@ -1134,9 +1134,11 @@ class TestRegex:
def test_validate_valid(self, klass, val):
klass(none_ok=True).validate(val)
@pytest.mark.parametrize('val', [r'(foo|bar))?baz[fis]h', '', '(' * 500],
ids=['unmatched parens', 'empty',
'too many parens'])
@pytest.mark.parametrize('val', [
pytest.param(r'(foo|bar))?baz[fis]h', id='unmatched parens'),
pytest.param('', id='empty'),
pytest.param('(' * 500, id='too many parens'),
])
def test_validate_invalid(self, klass, val):
with pytest.raises(configexc.ValidationError):
klass().validate(val)
@ -1255,9 +1257,10 @@ class TestFile:
'/home/foo/.config/', 'foobar')
@pytest.mark.parametrize('configtype, value, raises', [
(configtypes.File(), 'foobar', True),
(configtypes.File(required=False), 'foobar', False),
], ids=['file-foobar', 'file-optional-foobar'])
pytest.param(configtypes.File(), 'foobar', True, id='file-foobar'),
pytest.param(configtypes.File(required=False), 'foobar', False,
id='file-optional-foobar'),
])
def test_validate_rel_inexistent(self, os_mock, monkeypatch, configtype,
value, raises):
"""Test with a relative path and standarddir.config returning None."""

View File

@ -61,10 +61,10 @@ def url_widget(qtbot, monkeypatch, config_stub):
('http://username:secret%20password@test.com', 'http://username@test.com'),
('http://example.com%5b/', '(invalid URL!) http://example.com%5b/'),
# https://bugreports.qt.io/browse/QTBUG-60364
utils.qt58(('http://www.xn--80ak6aa92e.com',
'(unparseable URL!) http://www.аррӏе.com')),
utils.qt59(('http://www.xn--80ak6aa92e.com',
'http://www.xn--80ak6aa92e.com')),
pytest.param('http://www.xn--80ak6aa92e.com',
'(unparseable URL!) http://www.аррӏе.com', marks=utils.qt58),
pytest.param('http://www.xn--80ak6aa92e.com',
'http://www.xn--80ak6aa92e.com', marks=utils.qt59),
# IDN URL
('http://www.ä.com', '(www.xn--4ca.com) http://www.ä.com'),
(None, ''),

View File

@ -168,9 +168,9 @@ def test_rl_backward_word(text, expected, lineedit, bridge):
@pytest.mark.parametrize('text, expected', [
fixme(('<o>ne two', 'one| two')),
pytest.param('<o>ne two', 'one| two', marks=fixme),
('<o>ne two', 'one |two'), # wrong
fixme(('<one> two', 'one two|')),
pytest.param('<one> two', 'one two|', marks=fixme),
('<one> two', 'one |two'), # wrong
('one t<wo>', 'one two|')
])
@ -219,9 +219,9 @@ def test_rl_backward_delete_char(text, expected, lineedit, bridge):
@pytest.mark.parametrize('text, deleted, rest', [
('delete this| test', 'delete this', '| test'),
fixme(('delete <this> test', 'delete this', '| test')),
pytest.param('delete <this> test', 'delete this', '| test', marks=fixme),
('delete <this> test', 'delete ', '|this test'), # wrong
fixme(('f<oo>bar', 'foo', '|bar')),
pytest.param('f<oo>bar', 'foo', '|bar', marks=fixme),
('f<oo>bar', 'f', '|oobar'), # wrong
])
def test_rl_unix_line_discard(lineedit, bridge, text, deleted, rest):
@ -232,7 +232,8 @@ def test_rl_unix_line_discard(lineedit, bridge, text, deleted, rest):
@pytest.mark.parametrize('text, deleted, rest', [
('test |delete this', 'delete this', 'test |'),
fixme(('<test >delete this', 'test delete this', 'test |')),
pytest.param('<test >delete this', 'test delete this', 'test |',
marks=fixme),
('<test >delete this', 'test delete this', '|'), # wrong
])
def test_rl_kill_line(lineedit, bridge, text, deleted, rest):
@ -246,7 +247,8 @@ def test_rl_kill_line(lineedit, bridge, text, deleted, rest):
('test delete |foobar', 'delete ', 'test |foobar'),
('open -t github.com/foo/bar |', 'github.com/foo/bar ', 'open -t |'),
('open -t |github.com/foo/bar', '-t ', 'open |github.com/foo/bar'),
fixme(('test del<ete>foobar', 'delete', 'test |foobar')),
pytest.param('test del<ete>foobar', 'delete', 'test |foobar',
marks=fixme),
('test del<ete >foobar', 'del', 'test |ete foobar'), # wrong
])
def test_rl_unix_word_rubout(lineedit, bridge, text, deleted, rest):
@ -269,11 +271,14 @@ def test_rl_unix_filename_rubout(lineedit, bridge, text, deleted, rest):
@pytest.mark.parametrize('text, deleted, rest', [
fixme(('test foobar| delete', ' delete', 'test foobar|')),
pytest.param('test foobar| delete', ' delete', 'test foobar|',
marks=fixme),
('test foobar| delete', ' ', 'test foobar|delete'), # wrong
fixme(('test foo|delete bar', 'delete', 'test foo| bar')),
pytest.param('test foo|delete bar', 'delete', 'test foo| bar',
marks=fixme),
('test foo|delete bar', 'delete ', 'test foo|bar'), # wrong
fixme(('test foo<bar> delete', ' delete', 'test foobar|')),
pytest.param('test foo<bar> delete', ' delete', 'test foobar|',
marks=fixme),
('test foo<bar>delete', 'bardelete', 'test foo|'), # wrong
])
def test_rl_kill_word(lineedit, bridge, text, deleted, rest):
@ -287,7 +292,7 @@ def test_rl_kill_word(lineedit, bridge, text, deleted, rest):
('test delete |foobar', 'delete ', 'test |foobar'),
('open -t github.com/foo/bar |', 'bar ', 'open -t github.com/foo/|'),
('open -t |github.com/foo/bar', 't ', 'open -|github.com/foo/bar'),
fixme(('test del<ete>foobar', 'delete', 'test |foobar')),
pytest.param('test del<ete>foobar', 'delete', 'test |foobar', marks=fixme),
('test del<ete >foobar', 'del', 'test |ete foobar'), # wrong
('open foo/bar.baz|', 'baz', 'open foo/bar.|'),
])

View File

@ -165,9 +165,11 @@ class TestQFlagsKey:
@pytest.mark.parametrize('base, value, klass, expected', [
(Qt, Qt.AlignTop, None, 'AlignTop'),
fixme((Qt, Qt.AlignLeft | Qt.AlignTop, None, 'AlignLeft|AlignTop')),
pytest.param(Qt, Qt.AlignLeft | Qt.AlignTop, None,
'AlignLeft|AlignTop', marks=fixme),
(Qt, Qt.AlignCenter, None, 'AlignHCenter|AlignVCenter'),
fixme((Qt, 0x0021, Qt.Alignment, 'AlignLeft|AlignTop')),
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'),

View File

@ -180,8 +180,9 @@ class TestArguments:
"""Tests the --basedir argument."""
@pytest.mark.parametrize('typ', ['config', 'data', 'cache', 'download',
pytest.mark.linux('runtime')])
@pytest.mark.parametrize('typ', [
'config', 'data', 'cache', 'download',
pytest.param('runtime', marks=pytest.mark.linux)])
def test_basedir(self, tmpdir, typ):
"""Test --basedir."""
expected = str(tmpdir / typ)

View File

@ -340,9 +340,7 @@ def test_get_search_url_invalid(urlutils_config_stub, url):
(False, True, True, 'hello.'),
(False, True, False, 'site:cookies.com oatmeal raisin'),
# no DNS because bogus-IP
pytest.mark.xfail(qtutils.version_check('5.6.1'),
reason='Qt behavior changed')(
False, True, False, '31c3'),
(False, True, False, '31c3'),
(False, True, False, 'foo::bar'), # no DNS because of no host
# Valid search term with autosearch
(False, False, False, 'test foo'),
@ -363,6 +361,11 @@ def test_is_url(urlutils_config_stub, fake_dns, is_url, is_url_no_autosearch,
url: The URL to test, as a string.
auto_search: With which auto-search setting to test
"""
if (url == '31c3' and
auto_search == 'dns' and
qtutils.version_check('5.6.1')):
pytest.xfail("Qt behavior changed")
urlutils_config_stub.data['general']['auto-search'] = auto_search
if auto_search == 'dns':
if uses_dns:
@ -756,10 +759,12 @@ def test_data_url():
(QUrl('http://www.example.xn--p1ai'),
'(www.example.xn--p1ai) http://www.example.рф'),
# https://bugreports.qt.io/browse/QTBUG-60364
testutils.qt58((QUrl('http://www.xn--80ak6aa92e.com'),
'(unparseable URL!) http://www.аррӏе.com')),
testutils.qt59((QUrl('http://www.xn--80ak6aa92e.com'),
'http://www.xn--80ak6aa92e.com')),
pytest.param(QUrl('http://www.xn--80ak6aa92e.com'),
'(unparseable URL!) http://www.аррӏе.com',
marks=testutils.qt58),
pytest.param(QUrl('http://www.xn--80ak6aa92e.com'),
'http://www.xn--80ak6aa92e.com',
marks=testutils.qt59),
])
def test_safe_display_string(url, expected):
assert urlutils.safe_display_string(url) == expected

View File

@ -657,17 +657,19 @@ QUALNAME_OBJ = QualnameObj()
@pytest.mark.parametrize('obj, expected', [
(QUALNAME_OBJ, repr(QUALNAME_OBJ)), # instance - unknown
(QualnameObj, 'test_utils.QualnameObj'), # class
(QualnameObj.func, 'test_utils.QualnameObj.func'), # unbound method
(QualnameObj().func, 'test_utils.QualnameObj.func'), # bound method
(qualname_func, 'test_utils.qualname_func'), # function
(functools.partial(qualname_func, True), 'test_utils.qualname_func'),
(qutebrowser, 'qutebrowser'), # module
(qutebrowser.utils, 'qutebrowser.utils'), # submodule
(utils, 'qutebrowser.utils.utils'), # submodule (from-import)
], ids=['instance', 'class', 'unbound-method', 'bound-method', 'function',
'partial', 'module', 'submodule', 'from-import'])
pytest.param(QUALNAME_OBJ, repr(QUALNAME_OBJ), id='instance'),
pytest.param(QualnameObj, 'test_utils.QualnameObj', id='class'),
pytest.param(QualnameObj.func, 'test_utils.QualnameObj.func',
id='unbound-method'),
pytest.param(QualnameObj().func, 'test_utils.QualnameObj.func',
id='bound-method'),
pytest.param(qualname_func, 'test_utils.qualname_func', id='function'),
pytest.param(functools.partial(qualname_func, True),
'test_utils.qualname_func', id='partial'),
pytest.param(qutebrowser, 'qutebrowser', id='module'),
pytest.param(qutebrowser.utils, 'qutebrowser.utils', id='submodule'),
pytest.param(utils, 'qutebrowser.utils.utils', id='from-import'),
])
def test_qualname(obj, expected):
assert utils.qualname(obj) == expected