Merge pull request #19 from hackebrot/parametrize-sub-tests
Parametrize sub tests
This commit is contained in:
commit
987bab9960
@ -127,7 +127,7 @@ def split(s, keep=False):
|
||||
"""Split a string via ShellLexer.
|
||||
|
||||
Args:
|
||||
keep: Whether to keep are special chars in the split output.
|
||||
keep: Whether to keep special chars in the split output.
|
||||
"""
|
||||
lexer = ShellLexer(s)
|
||||
lexer.keep = keep
|
||||
|
@ -63,44 +63,27 @@ class TestSplitCount:
|
||||
|
||||
"""Test the _split_count method.
|
||||
|
||||
Attributes:
|
||||
kp: The BaseKeyParser we're testing.
|
||||
Class Attributes:
|
||||
TESTS: list of parameters for the tests, as tuples of
|
||||
(input_key, supports_count, expected)
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.kp = basekeyparser.BaseKeyParser(0, supports_count=True)
|
||||
TESTS = [
|
||||
# (input_key, supports_count, expected)
|
||||
('10', True, (10, '')),
|
||||
('10foo', True, (10, 'foo')),
|
||||
('-1foo', True, (None, '-1foo')),
|
||||
('10e4foo', True, (10, 'e4foo')),
|
||||
('foo', True, (None, 'foo')),
|
||||
('10foo', False, (None, '10foo')),
|
||||
]
|
||||
|
||||
def test_onlycount(self):
|
||||
@pytest.mark.parametrize('input_key, supports_count, expected', TESTS)
|
||||
def test_splitcount(self, input_key, supports_count, expected):
|
||||
"""Test split_count with only a count."""
|
||||
self.kp._keystring = '10'
|
||||
assert self.kp._split_count() == (10, '')
|
||||
|
||||
def test_normalcount(self):
|
||||
"""Test split_count with count and text."""
|
||||
self.kp._keystring = '10foo'
|
||||
assert self.kp._split_count() == (10, 'foo')
|
||||
|
||||
def test_minuscount(self):
|
||||
"""Test split_count with a negative count."""
|
||||
self.kp._keystring = '-1foo'
|
||||
assert self.kp._split_count() == (None, '-1foo')
|
||||
|
||||
def test_expcount(self):
|
||||
"""Test split_count with an exponential count."""
|
||||
self.kp._keystring = '10e4foo'
|
||||
assert self.kp._split_count() == (10, 'e4foo')
|
||||
|
||||
def test_nocount(self):
|
||||
"""Test split_count with only a command."""
|
||||
self.kp._keystring = 'foo'
|
||||
assert self.kp._split_count() == (None, 'foo')
|
||||
|
||||
def test_nosupport(self):
|
||||
"""Test split_count with a count when counts aren't supported."""
|
||||
self.kp._supports_count = False
|
||||
self.kp._keystring = '10foo'
|
||||
assert self.kp._split_count() == (None, '10foo')
|
||||
kp = basekeyparser.BaseKeyParser(0, supports_count=supports_count)
|
||||
kp._keystring = input_key
|
||||
assert kp._split_count() == expected
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('fake_keyconfig', 'mock_timer')
|
||||
|
@ -18,8 +18,9 @@
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Tests for qutebrowser.misc.split."""
|
||||
import collections
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from qutebrowser.misc import split
|
||||
|
||||
@ -29,7 +30,7 @@ from qutebrowser.misc import split
|
||||
|
||||
# Format: input/split|output|without|keep/split|output|with|keep/
|
||||
|
||||
test_data = r"""
|
||||
test_data_str = r"""
|
||||
one two/one|two/one| two/
|
||||
one "two three" four/one|two three|four/one| "two three"| four/
|
||||
one 'two three' four/one|two three|four/one| 'two three'| four/
|
||||
@ -104,36 +105,56 @@ foo\ bar/foo bar/foo\ bar/
|
||||
"""
|
||||
|
||||
|
||||
class SplitTests(unittest.TestCase):
|
||||
def _parse_split_test_data_str():
|
||||
"""
|
||||
Parse the test data set into a namedtuple to use in tests.
|
||||
|
||||
Returns:
|
||||
A list of namedtuples with str attributes: input, keep, no_keep
|
||||
"""
|
||||
tuple_class = collections.namedtuple('TestCase', 'input, keep, no_keep')
|
||||
|
||||
result = []
|
||||
for line in test_data_str.splitlines():
|
||||
if not line:
|
||||
continue
|
||||
data = line.split('/')
|
||||
item = tuple_class(input=data[0], keep=data[1].split('|'),
|
||||
no_keep=data[2].split('|'))
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
|
||||
class TestSplit:
|
||||
|
||||
"""Test split."""
|
||||
|
||||
def test_split(self):
|
||||
@pytest.fixture(params=_parse_split_test_data_str())
|
||||
def split_test_case(self, request):
|
||||
"""Fixture to automatically parametrize all depending tests.
|
||||
|
||||
It will use the test data from test_data_str, parsed using
|
||||
_parse_split_test_data_str().
|
||||
"""
|
||||
return request.param
|
||||
|
||||
def test_split(self, split_test_case):
|
||||
"""Test splitting."""
|
||||
for case in test_data.strip().splitlines():
|
||||
cmd, out = case.split('/')[:-2]
|
||||
with self.subTest(cmd=cmd):
|
||||
items = split.split(cmd)
|
||||
self.assertEqual(items, out.split('|'))
|
||||
items = split.split(split_test_case.input)
|
||||
assert items == split_test_case.keep
|
||||
|
||||
def test_split_keep_original(self):
|
||||
def test_split_keep_original(self, split_test_case):
|
||||
"""Test if splitting with keep=True yields the original string."""
|
||||
for case in test_data.strip().splitlines():
|
||||
cmd = case.split('/')[0]
|
||||
with self.subTest(cmd=cmd):
|
||||
items = split.split(cmd, keep=True)
|
||||
self.assertEqual(''.join(items), cmd)
|
||||
items = split.split(split_test_case.input, keep=True)
|
||||
assert ''.join(items) == split_test_case.input
|
||||
|
||||
def test_split_keep(self):
|
||||
def test_split_keep(self, split_test_case):
|
||||
"""Test splitting with keep=True."""
|
||||
for case in test_data.strip().splitlines():
|
||||
cmd, _mid, out = case.split('/')[:-1]
|
||||
with self.subTest(cmd=cmd):
|
||||
items = split.split(cmd, keep=True)
|
||||
self.assertEqual(items, out.split('|'))
|
||||
items = split.split(split_test_case.input, keep=True)
|
||||
assert items == split_test_case.no_keep
|
||||
|
||||
|
||||
class SimpleSplitTests(unittest.TestCase):
|
||||
class TestSimpleSplit:
|
||||
|
||||
"""Test simple_split."""
|
||||
|
||||
@ -145,27 +166,20 @@ class SimpleSplitTests(unittest.TestCase):
|
||||
'foo\nbar': ['foo', '\nbar'],
|
||||
}
|
||||
|
||||
def test_str_split(self):
|
||||
@pytest.mark.parametrize('test', TESTS)
|
||||
def test_str_split(self, test):
|
||||
"""Test if the behavior matches str.split."""
|
||||
for test in self.TESTS:
|
||||
with self.subTest(string=test):
|
||||
self.assertEqual(split.simple_split(test),
|
||||
test.rstrip().split())
|
||||
assert split.simple_split(test) == test.rstrip().split()
|
||||
|
||||
def test_str_split_maxsplit_1(self):
|
||||
"""Test if the behavior matches str.split with maxsplit=1."""
|
||||
string = "foo bar baz"
|
||||
self.assertEqual(split.simple_split(string, maxsplit=1),
|
||||
string.rstrip().split(maxsplit=1))
|
||||
@pytest.mark.parametrize('s, maxsplit',
|
||||
[("foo bar baz", 1), (" foo bar baz ", 0)])
|
||||
def test_str_split_maxsplit(self, s, maxsplit):
|
||||
"""Test if the behavior matches str.split with given maxsplit."""
|
||||
actual = split.simple_split(s, maxsplit=maxsplit)
|
||||
expected = s.rstrip().split(maxsplit=maxsplit)
|
||||
assert actual == expected
|
||||
|
||||
def test_str_split_maxsplit_0(self):
|
||||
"""Test if the behavior matches str.split with maxsplit=0."""
|
||||
string = " foo bar baz "
|
||||
self.assertEqual(split.simple_split(string, maxsplit=0),
|
||||
string.rstrip().split(maxsplit=0))
|
||||
|
||||
def test_split_keep(self):
|
||||
@pytest.mark.parametrize('test, expected', TESTS.items())
|
||||
def test_split_keep(self, test, expected):
|
||||
"""Test splitting with keep=True."""
|
||||
for test, expected in self.TESTS.items():
|
||||
with self.subTest(string=test):
|
||||
self.assertEqual(split.simple_split(test, keep=True), expected)
|
||||
assert split.simple_split(test, keep=True) == expected
|
||||
|
70
tests/utils/overflow_test_cases.py
Normal file
70
tests/utils/overflow_test_cases.py
Normal file
@ -0,0 +1,70 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
"""
|
||||
Provides test data for overflow checking.
|
||||
|
||||
Module attributes:
|
||||
INT32_MIN: Minimum valid value for a signed int32.
|
||||
INT32_MAX: Maximum valid value for a signed int32.
|
||||
INT64_MIN: Minimum valid value for a signed int64.
|
||||
INT64_MAX: Maximum valid value for a signed int64.
|
||||
GOOD_VALUES: A dict of types mapped to a list of good values.
|
||||
BAD_VALUES: A dict of types mapped to a list of bad values.
|
||||
"""
|
||||
|
||||
INT32_MIN = -(2 ** 31)
|
||||
INT32_MAX = 2 ** 31 - 1
|
||||
INT64_MIN = -(2 ** 63)
|
||||
INT64_MAX = 2 ** 63 - 1
|
||||
|
||||
GOOD_VALUES = {
|
||||
'int': [-1, 0, 1, 23.42, INT32_MIN, INT32_MAX],
|
||||
'int64': [-1, 0, 1, 23.42, INT64_MIN, INT64_MAX],
|
||||
}
|
||||
|
||||
BAD_VALUES = {
|
||||
'int': [(INT32_MIN - 1, INT32_MIN),
|
||||
(INT32_MAX + 1, INT32_MAX),
|
||||
(float(INT32_MAX + 1), INT32_MAX)],
|
||||
'int64': [(INT64_MIN - 1, INT64_MIN),
|
||||
(INT64_MAX + 1, INT64_MAX),
|
||||
(float(INT64_MAX + 1), INT64_MAX)],
|
||||
}
|
||||
|
||||
|
||||
def iter_good_values():
|
||||
"""Yield "good" (C data type, value) tuples.
|
||||
|
||||
Those should pass overflow checking.
|
||||
"""
|
||||
for ctype, values in GOOD_VALUES.items():
|
||||
for value in values:
|
||||
yield ctype, value
|
||||
|
||||
|
||||
def iter_bad_values():
|
||||
"""Yield pairs of "bad" (C type, value, repl) tuples.
|
||||
|
||||
Theose should not pass overflow checking. The third value is the value they
|
||||
should be replaced with if overflow checking should not be fatal.
|
||||
"""
|
||||
for ctype, values in BAD_VALUES.items():
|
||||
for value, repl in values:
|
||||
yield ctype, value, repl
|
@ -20,107 +20,74 @@
|
||||
"""Tests for qutebrowser.utils.qtutils."""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from qutebrowser import qutebrowser
|
||||
from qutebrowser.utils import qtutils
|
||||
import overflow_test_cases
|
||||
|
||||
|
||||
class CheckOverflowTests(unittest.TestCase):
|
||||
class TestCheckOverflow:
|
||||
|
||||
"""Test check_overflow.
|
||||
"""Test check_overflow."""
|
||||
|
||||
Class attributes:
|
||||
INT32_MIN: Minimum valid value for a signed int32.
|
||||
INT32_MAX: Maximum valid value for a signed int32.
|
||||
INT64_MIN: Minimum valid value for a signed int64.
|
||||
INT64_MAX: Maximum valid value for a signed int64.
|
||||
GOOD_VALUES: A dict of types mapped to a list of good values.
|
||||
BAD_VALUES: A dict of types mapped to a list of bad values.
|
||||
"""
|
||||
|
||||
INT32_MIN = -(2 ** 31)
|
||||
INT32_MAX = 2 ** 31 - 1
|
||||
INT64_MIN = -(2 ** 63)
|
||||
INT64_MAX = 2 ** 63 - 1
|
||||
|
||||
GOOD_VALUES = {
|
||||
'int': [-1, 0, 1, 23.42, INT32_MIN, INT32_MAX],
|
||||
'int64': [-1, 0, 1, 23.42, INT64_MIN, INT64_MAX],
|
||||
}
|
||||
|
||||
BAD_VALUES = {
|
||||
'int': [(INT32_MIN - 1, INT32_MIN),
|
||||
(INT32_MAX + 1, INT32_MAX),
|
||||
(float(INT32_MAX + 1), INT32_MAX)],
|
||||
'int64': [(INT64_MIN - 1, INT64_MIN),
|
||||
(INT64_MAX + 1, INT64_MAX),
|
||||
(float(INT64_MAX + 1), INT64_MAX)],
|
||||
}
|
||||
|
||||
def test_good_values(self):
|
||||
@pytest.mark.parametrize('ctype, val',
|
||||
overflow_test_cases.iter_good_values())
|
||||
def test_good_values(self, ctype, val):
|
||||
"""Test values which are inside bounds."""
|
||||
for ctype, vals in self.GOOD_VALUES.items():
|
||||
for val in vals:
|
||||
with self.subTest(ctype=ctype, val=val):
|
||||
qtutils.check_overflow(val, ctype)
|
||||
|
||||
def test_bad_values_fatal(self):
|
||||
@pytest.mark.parametrize('ctype, val',
|
||||
[(ctype, val) for (ctype, val, _) in
|
||||
overflow_test_cases.iter_bad_values()])
|
||||
def test_bad_values_fatal(self, ctype, val):
|
||||
"""Test values which are outside bounds with fatal=True."""
|
||||
for ctype, vals in self.BAD_VALUES.items():
|
||||
for (val, _) in vals:
|
||||
with self.subTest(ctype=ctype, val=val):
|
||||
with self.assertRaises(OverflowError):
|
||||
with pytest.raises(OverflowError):
|
||||
qtutils.check_overflow(val, ctype)
|
||||
|
||||
def test_bad_values_nonfatal(self):
|
||||
@pytest.mark.parametrize('ctype, val, repl',
|
||||
overflow_test_cases.iter_bad_values())
|
||||
def test_bad_values_nonfatal(self, ctype, val, repl):
|
||||
"""Test values which are outside bounds with fatal=False."""
|
||||
for ctype, vals in self.BAD_VALUES.items():
|
||||
for (val, replacement) in vals:
|
||||
with self.subTest(ctype=ctype, val=val):
|
||||
newval = qtutils.check_overflow(val, ctype, fatal=False)
|
||||
self.assertEqual(newval, replacement)
|
||||
assert newval == repl
|
||||
|
||||
|
||||
def argparser_exit(status=0, message=None): # pylint: disable=unused-argument
|
||||
"""Function to monkey-patch .exit() of the argparser so it doesn't exit."""
|
||||
raise Exception
|
||||
|
||||
|
||||
class GetQtArgsTests(unittest.TestCase):
|
||||
class TestGetQtArgs:
|
||||
|
||||
"""Tests for get_args."""
|
||||
|
||||
def setUp(self):
|
||||
self.parser = qutebrowser.get_argparser()
|
||||
self.parser.exit = argparser_exit
|
||||
@pytest.fixture
|
||||
def parser(self, mocker):
|
||||
"""Fixture to provide an argparser.
|
||||
|
||||
def test_no_qt_args(self):
|
||||
Monkey-patches .exit() of the argparser so it doesn't exit on errors.
|
||||
"""
|
||||
parser = qutebrowser.get_argparser()
|
||||
mocker.patch.object(parser, 'exit', side_effect=Exception)
|
||||
return parser
|
||||
|
||||
def test_no_qt_args(self, parser):
|
||||
"""Test commandline with no Qt arguments given."""
|
||||
args = self.parser.parse_args(['--debug'])
|
||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0]])
|
||||
args = parser.parse_args(['--debug'])
|
||||
assert qtutils.get_args(args) == [sys.argv[0]]
|
||||
|
||||
def test_qt_flag(self):
|
||||
def test_qt_flag(self, parser):
|
||||
"""Test commandline with a Qt flag."""
|
||||
args = self.parser.parse_args(['--debug', '--qt-reverse', '--nocolor'])
|
||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0], '-reverse'])
|
||||
args = parser.parse_args(['--debug', '--qt-reverse', '--nocolor'])
|
||||
assert qtutils.get_args(args) == [sys.argv[0], '-reverse']
|
||||
|
||||
def test_qt_arg(self):
|
||||
def test_qt_arg(self, parser):
|
||||
"""Test commandline with a Qt argument."""
|
||||
args = self.parser.parse_args(['--qt-stylesheet', 'foobar'])
|
||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0], '-stylesheet',
|
||||
'foobar'])
|
||||
args = parser.parse_args(['--qt-stylesheet', 'foobar'])
|
||||
assert qtutils.get_args(args) == [sys.argv[0], '-stylesheet', 'foobar']
|
||||
|
||||
def test_qt_both(self):
|
||||
def test_qt_both(self, parser):
|
||||
"""Test commandline with a Qt argument and flag."""
|
||||
args = self.parser.parse_args(['--qt-stylesheet', 'foobar',
|
||||
'--qt-reverse'])
|
||||
args = parser.parse_args(['--qt-stylesheet', 'foobar', '--qt-reverse'])
|
||||
qt_args = qtutils.get_args(args)
|
||||
self.assertEqual(qt_args[0], sys.argv[0])
|
||||
self.assertIn('-reverse', qt_args)
|
||||
self.assertIn('-stylesheet', qt_args)
|
||||
self.assertIn('foobar', qt_args)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
assert qt_args[0] == sys.argv[0]
|
||||
assert '-reverse' in qt_args
|
||||
assert '-stylesheet' in qt_args
|
||||
assert 'foobar' in qt_args
|
||||
|
Loading…
Reference in New Issue
Block a user