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.
|
"""Split a string via ShellLexer.
|
||||||
|
|
||||||
Args:
|
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 = ShellLexer(s)
|
||||||
lexer.keep = keep
|
lexer.keep = keep
|
||||||
|
@ -63,44 +63,27 @@ class TestSplitCount:
|
|||||||
|
|
||||||
"""Test the _split_count method.
|
"""Test the _split_count method.
|
||||||
|
|
||||||
Attributes:
|
Class Attributes:
|
||||||
kp: The BaseKeyParser we're testing.
|
TESTS: list of parameters for the tests, as tuples of
|
||||||
|
(input_key, supports_count, expected)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
TESTS = [
|
||||||
def setup(self):
|
# (input_key, supports_count, expected)
|
||||||
self.kp = basekeyparser.BaseKeyParser(0, supports_count=True)
|
('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."""
|
"""Test split_count with only a count."""
|
||||||
self.kp._keystring = '10'
|
kp = basekeyparser.BaseKeyParser(0, supports_count=supports_count)
|
||||||
assert self.kp._split_count() == (10, '')
|
kp._keystring = input_key
|
||||||
|
assert kp._split_count() == expected
|
||||||
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')
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('fake_keyconfig', 'mock_timer')
|
@pytest.mark.usefixtures('fake_keyconfig', 'mock_timer')
|
||||||
|
@ -18,8 +18,9 @@
|
|||||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
"""Tests for qutebrowser.misc.split."""
|
"""Tests for qutebrowser.misc.split."""
|
||||||
|
import collections
|
||||||
|
|
||||||
import unittest
|
import pytest
|
||||||
|
|
||||||
from qutebrowser.misc import split
|
from qutebrowser.misc import split
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ from qutebrowser.misc import split
|
|||||||
|
|
||||||
# Format: input/split|output|without|keep/split|output|with|keep/
|
# 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/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/
|
||||||
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."""
|
"""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."""
|
"""Test splitting."""
|
||||||
for case in test_data.strip().splitlines():
|
items = split.split(split_test_case.input)
|
||||||
cmd, out = case.split('/')[:-2]
|
assert items == split_test_case.keep
|
||||||
with self.subTest(cmd=cmd):
|
|
||||||
items = split.split(cmd)
|
|
||||||
self.assertEqual(items, out.split('|'))
|
|
||||||
|
|
||||||
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."""
|
"""Test if splitting with keep=True yields the original string."""
|
||||||
for case in test_data.strip().splitlines():
|
items = split.split(split_test_case.input, keep=True)
|
||||||
cmd = case.split('/')[0]
|
assert ''.join(items) == split_test_case.input
|
||||||
with self.subTest(cmd=cmd):
|
|
||||||
items = split.split(cmd, keep=True)
|
|
||||||
self.assertEqual(''.join(items), cmd)
|
|
||||||
|
|
||||||
def test_split_keep(self):
|
def test_split_keep(self, split_test_case):
|
||||||
"""Test splitting with keep=True."""
|
"""Test splitting with keep=True."""
|
||||||
for case in test_data.strip().splitlines():
|
items = split.split(split_test_case.input, keep=True)
|
||||||
cmd, _mid, out = case.split('/')[:-1]
|
assert items == split_test_case.no_keep
|
||||||
with self.subTest(cmd=cmd):
|
|
||||||
items = split.split(cmd, keep=True)
|
|
||||||
self.assertEqual(items, out.split('|'))
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleSplitTests(unittest.TestCase):
|
class TestSimpleSplit:
|
||||||
|
|
||||||
"""Test simple_split."""
|
"""Test simple_split."""
|
||||||
|
|
||||||
@ -145,27 +166,20 @@ class SimpleSplitTests(unittest.TestCase):
|
|||||||
'foo\nbar': ['foo', '\nbar'],
|
'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."""
|
"""Test if the behavior matches str.split."""
|
||||||
for test in self.TESTS:
|
assert split.simple_split(test) == test.rstrip().split()
|
||||||
with self.subTest(string=test):
|
|
||||||
self.assertEqual(split.simple_split(test),
|
|
||||||
test.rstrip().split())
|
|
||||||
|
|
||||||
def test_str_split_maxsplit_1(self):
|
@pytest.mark.parametrize('s, maxsplit',
|
||||||
"""Test if the behavior matches str.split with maxsplit=1."""
|
[("foo bar baz", 1), (" foo bar baz ", 0)])
|
||||||
string = "foo bar baz"
|
def test_str_split_maxsplit(self, s, maxsplit):
|
||||||
self.assertEqual(split.simple_split(string, maxsplit=1),
|
"""Test if the behavior matches str.split with given maxsplit."""
|
||||||
string.rstrip().split(maxsplit=1))
|
actual = split.simple_split(s, maxsplit=maxsplit)
|
||||||
|
expected = s.rstrip().split(maxsplit=maxsplit)
|
||||||
|
assert actual == expected
|
||||||
|
|
||||||
def test_str_split_maxsplit_0(self):
|
@pytest.mark.parametrize('test, expected', TESTS.items())
|
||||||
"""Test if the behavior matches str.split with maxsplit=0."""
|
def test_split_keep(self, test, expected):
|
||||||
string = " foo bar baz "
|
|
||||||
self.assertEqual(split.simple_split(string, maxsplit=0),
|
|
||||||
string.rstrip().split(maxsplit=0))
|
|
||||||
|
|
||||||
def test_split_keep(self):
|
|
||||||
"""Test splitting with keep=True."""
|
"""Test splitting with keep=True."""
|
||||||
for test, expected in self.TESTS.items():
|
assert split.simple_split(test, keep=True) == expected
|
||||||
with self.subTest(string=test):
|
|
||||||
self.assertEqual(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."""
|
"""Tests for qutebrowser.utils.qtutils."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from qutebrowser import qutebrowser
|
from qutebrowser import qutebrowser
|
||||||
from qutebrowser.utils import qtutils
|
from qutebrowser.utils import qtutils
|
||||||
|
import overflow_test_cases
|
||||||
|
|
||||||
|
|
||||||
class CheckOverflowTests(unittest.TestCase):
|
class TestCheckOverflow:
|
||||||
|
|
||||||
"""Test check_overflow.
|
"""Test check_overflow."""
|
||||||
|
|
||||||
Class attributes:
|
@pytest.mark.parametrize('ctype, val',
|
||||||
INT32_MIN: Minimum valid value for a signed int32.
|
overflow_test_cases.iter_good_values())
|
||||||
INT32_MAX: Maximum valid value for a signed int32.
|
def test_good_values(self, ctype, val):
|
||||||
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):
|
|
||||||
"""Test values which are inside bounds."""
|
"""Test values which are inside bounds."""
|
||||||
for ctype, vals in self.GOOD_VALUES.items():
|
qtutils.check_overflow(val, ctype)
|
||||||
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."""
|
"""Test values which are outside bounds with fatal=True."""
|
||||||
for ctype, vals in self.BAD_VALUES.items():
|
with pytest.raises(OverflowError):
|
||||||
for (val, _) in vals:
|
qtutils.check_overflow(val, ctype)
|
||||||
with self.subTest(ctype=ctype, val=val):
|
|
||||||
with self.assertRaises(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."""
|
"""Test values which are outside bounds with fatal=False."""
|
||||||
for ctype, vals in self.BAD_VALUES.items():
|
newval = qtutils.check_overflow(val, ctype, fatal=False)
|
||||||
for (val, replacement) in vals:
|
assert newval == repl
|
||||||
with self.subTest(ctype=ctype, val=val):
|
|
||||||
newval = qtutils.check_overflow(val, ctype, fatal=False)
|
|
||||||
self.assertEqual(newval, replacement)
|
|
||||||
|
|
||||||
|
|
||||||
def argparser_exit(status=0, message=None): # pylint: disable=unused-argument
|
class TestGetQtArgs:
|
||||||
"""Function to monkey-patch .exit() of the argparser so it doesn't exit."""
|
|
||||||
raise Exception
|
|
||||||
|
|
||||||
|
|
||||||
class GetQtArgsTests(unittest.TestCase):
|
|
||||||
|
|
||||||
"""Tests for get_args."""
|
"""Tests for get_args."""
|
||||||
|
|
||||||
def setUp(self):
|
@pytest.fixture
|
||||||
self.parser = qutebrowser.get_argparser()
|
def parser(self, mocker):
|
||||||
self.parser.exit = argparser_exit
|
"""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."""
|
"""Test commandline with no Qt arguments given."""
|
||||||
args = self.parser.parse_args(['--debug'])
|
args = parser.parse_args(['--debug'])
|
||||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0]])
|
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."""
|
"""Test commandline with a Qt flag."""
|
||||||
args = self.parser.parse_args(['--debug', '--qt-reverse', '--nocolor'])
|
args = parser.parse_args(['--debug', '--qt-reverse', '--nocolor'])
|
||||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0], '-reverse'])
|
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."""
|
"""Test commandline with a Qt argument."""
|
||||||
args = self.parser.parse_args(['--qt-stylesheet', 'foobar'])
|
args = parser.parse_args(['--qt-stylesheet', 'foobar'])
|
||||||
self.assertEqual(qtutils.get_args(args), [sys.argv[0], '-stylesheet',
|
assert qtutils.get_args(args) == [sys.argv[0], '-stylesheet', 'foobar']
|
||||||
'foobar'])
|
|
||||||
|
|
||||||
def test_qt_both(self):
|
def test_qt_both(self, parser):
|
||||||
"""Test commandline with a Qt argument and flag."""
|
"""Test commandline with a Qt argument and flag."""
|
||||||
args = self.parser.parse_args(['--qt-stylesheet', 'foobar',
|
args = parser.parse_args(['--qt-stylesheet', 'foobar', '--qt-reverse'])
|
||||||
'--qt-reverse'])
|
|
||||||
qt_args = qtutils.get_args(args)
|
qt_args = qtutils.get_args(args)
|
||||||
self.assertEqual(qt_args[0], sys.argv[0])
|
assert qt_args[0] == sys.argv[0]
|
||||||
self.assertIn('-reverse', qt_args)
|
assert '-reverse' in qt_args
|
||||||
self.assertIn('-stylesheet', qt_args)
|
assert '-stylesheet' in qt_args
|
||||||
self.assertIn('foobar', qt_args)
|
assert 'foobar' in qt_args
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
unittest.main()
|
|
||||||
|
Loading…
Reference in New Issue
Block a user