track untested rules
Report untested rules as errors. Provide a flag to ignore untested rules. Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
parent
e7c0b47795
commit
d5b75fae18
@ -27,8 +27,11 @@ from whereto import rules
|
|||||||
def process_tests(ruleset, tests):
|
def process_tests(ruleset, tests):
|
||||||
"""Run the tests against the ruleset and return the results.
|
"""Run the tests against the ruleset and return the results.
|
||||||
|
|
||||||
Results are generated as tuples containing the inputs that did not
|
The return value is a tuple containing a list of tuples with the
|
||||||
match the expected value. The first element is the test tuple
|
inputs that did not match the expected value, and a set containing
|
||||||
|
the line numbers of the rules that never matched an input test.
|
||||||
|
|
||||||
|
The first element of the mismatched tuples is the test tuple
|
||||||
(line, input, expected), and the second element is the list of any
|
(line, input, expected), and the second element is the list of any
|
||||||
rules that did match the input pattern.
|
rules that did match the input pattern.
|
||||||
|
|
||||||
@ -36,17 +39,44 @@ def process_tests(ruleset, tests):
|
|||||||
:type ruleset: RuleSet
|
:type ruleset: RuleSet
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
used = set()
|
||||||
|
mismatches = []
|
||||||
for linenum, input, code, expected in tests:
|
for linenum, input, code, expected in tests:
|
||||||
matches = list(ruleset.match(input))
|
matches = list(ruleset.match(input))
|
||||||
if len(matches) == 1:
|
if len(matches) == 1:
|
||||||
match = matches[0]
|
match = matches[0]
|
||||||
if (code, expected) == match[1:]:
|
if (code, expected) == match[1:]:
|
||||||
|
used.add(match[0])
|
||||||
continue
|
continue
|
||||||
yield ((linenum, input, code, expected), matches)
|
mismatches.append(
|
||||||
|
((linenum, input, code, expected), matches)
|
||||||
|
)
|
||||||
|
untested = set(ruleset.all_ids) - used
|
||||||
|
return (mismatches, untested)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
arg_parser = argparse.ArgumentParser()
|
arg_parser = argparse.ArgumentParser()
|
||||||
|
group = arg_parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
|
'--ignore-untested',
|
||||||
|
action='store_false',
|
||||||
|
dest='error_untested',
|
||||||
|
default=True,
|
||||||
|
help='ignore untested rules',
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
'--error-untested',
|
||||||
|
action='store_true',
|
||||||
|
dest='error_untested',
|
||||||
|
help='error if there are untested rules',
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
'-q', '--quiet',
|
||||||
|
action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='run quietly',
|
||||||
|
)
|
||||||
arg_parser.add_argument(
|
arg_parser.add_argument(
|
||||||
'htaccess_file',
|
'htaccess_file',
|
||||||
help='file with rewrite rules',
|
help='file with rewrite rules',
|
||||||
@ -69,7 +99,8 @@ def main():
|
|||||||
]
|
]
|
||||||
|
|
||||||
failures = 0
|
failures = 0
|
||||||
for test, matches in process_tests(ruleset, tests):
|
mismatches, untested = process_tests(ruleset, tests)
|
||||||
|
for test, matches in mismatches:
|
||||||
failures += 1
|
failures += 1
|
||||||
if not matches:
|
if not matches:
|
||||||
print('No rule matched test on line {}: {}'.format(
|
print('No rule matched test on line {}: {}'.format(
|
||||||
@ -82,6 +113,15 @@ def main():
|
|||||||
for match in matches:
|
for match in matches:
|
||||||
print(' {}'.format(ruleset[match[0]]))
|
print(' {}'.format(ruleset[match[0]]))
|
||||||
|
|
||||||
|
if untested:
|
||||||
|
if not args.quiet:
|
||||||
|
print('')
|
||||||
|
for linenum in sorted(untested):
|
||||||
|
if not args.quiet:
|
||||||
|
print('Untested rule: {}'.format(ruleset[linenum]))
|
||||||
|
if args.error_untested:
|
||||||
|
failures += 1
|
||||||
|
|
||||||
if failures:
|
if failures:
|
||||||
print('\n{} failures'.format(failures))
|
print('\n{} failures'.format(failures))
|
||||||
return 1
|
return 1
|
||||||
|
@ -96,6 +96,10 @@ class RuleSet(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self._rules)
|
return iter(self._rules)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def all_ids(self):
|
||||||
|
return list(self._by_num.keys())
|
||||||
|
|
||||||
def match(self, path):
|
def match(self, path):
|
||||||
for rule in self:
|
for rule in self:
|
||||||
m = rule.match(path)
|
m = rule.match(path)
|
||||||
|
@ -28,11 +28,11 @@ class TestProcessTests(base.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_one_match(self):
|
def test_one_match(self):
|
||||||
actual = list(app.process_tests(
|
actual = app.process_tests(
|
||||||
self.ruleset,
|
self.ruleset,
|
||||||
[(1, '/path', '301', '/new/path')],
|
[(1, '/path', '301', '/new/path')],
|
||||||
))
|
)
|
||||||
expected = []
|
expected = ([], set())
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
|
||||||
def test_two_matches(self):
|
def test_two_matches(self):
|
||||||
@ -40,13 +40,14 @@ class TestProcessTests(base.TestCase):
|
|||||||
2,
|
2,
|
||||||
'redirect', '301', '/path', '/duplicate/redirect',
|
'redirect', '301', '/path', '/duplicate/redirect',
|
||||||
)
|
)
|
||||||
actual = list(app.process_tests(
|
actual = app.process_tests(
|
||||||
self.ruleset,
|
self.ruleset,
|
||||||
[(1, '/path', '301', '/new/path')],
|
[(1, '/path', '301', '/new/path')],
|
||||||
))
|
)
|
||||||
expected = [
|
expected = (
|
||||||
((1, '/path', '301', '/new/path'),
|
[((1, '/path', '301', '/new/path'),
|
||||||
[(1, '301', '/new/path'),
|
[(1, '301', '/new/path'),
|
||||||
(2, '301', '/duplicate/redirect')])
|
(2, '301', '/duplicate/redirect')])],
|
||||||
]
|
{1, 2},
|
||||||
|
)
|
||||||
self.assertEqual(expected, actual)
|
self.assertEqual(expected, actual)
|
||||||
|
@ -156,6 +156,18 @@ class TestRuleSet(base.TestCase):
|
|||||||
self.assertEqual(1, len(self.ruleset._rules))
|
self.assertEqual(1, len(self.ruleset._rules))
|
||||||
self.assertIsInstance(self.ruleset._rules[0], rules.RedirectMatch)
|
self.assertIsInstance(self.ruleset._rules[0], rules.RedirectMatch)
|
||||||
|
|
||||||
|
def test_all_ids(self):
|
||||||
|
self.ruleset.add(
|
||||||
|
1,
|
||||||
|
'redirect', '301', '/path', '/new/path',
|
||||||
|
)
|
||||||
|
self.assertEqual([1], self.ruleset.all_ids)
|
||||||
|
self.ruleset.add(
|
||||||
|
2,
|
||||||
|
'redirect', '301', '/path', '/other/path',
|
||||||
|
)
|
||||||
|
self.assertEqual([1, 2], self.ruleset.all_ids)
|
||||||
|
|
||||||
def test_match_one(self):
|
def test_match_one(self):
|
||||||
self.ruleset.add(
|
self.ruleset.add(
|
||||||
1,
|
1,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user