Skip to content

Commit b5d95b7

Browse files
authored
Merge pull request #72 from gaoflow/fix-parse-nth-invalid-crash
Return None instead of crashing on invalid An+B input
2 parents f295a49 + 47e05ab commit b5d95b7

2 files changed

Lines changed: 19 additions & 3 deletions

File tree

tests/test_tinycss2.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,20 @@ def test_nth(input):
153153
return parse_nth(input)
154154

155155

156+
@pytest.mark.parametrize('invalid', ['+', '+/**/', 'n+', 'n +', '-n-', '2n +'])
157+
def test_nth_invalid_does_not_crash(invalid):
158+
# Truncated/invalid An+B fragments must return None per parse_nth's
159+
# documented contract, not raise StopIteration or AttributeError.
160+
assert parse_nth(invalid) is None
161+
162+
163+
def test_nth_leading_plus_whitespace_still_invalid():
164+
# The fix for the above must not make '+ n' (whitespace after a leading
165+
# '+') accidentally valid: only '+n' is a valid nth expression.
166+
assert parse_nth('+n') == (1, 0)
167+
assert parse_nth('+ n') is None
168+
169+
156170
def _number(value):
157171
if value is None:
158172
return 'none'

tinycss2/nth.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ def parse_nth(input):
5959
if match:
6060
return parse_end(tokens, 1, int(match.group(1)))
6161
elif token == '+':
62-
token = next(tokens) # Whitespace after an initial '+' is invalid.
63-
if token.type == 'ident':
62+
# Whitespace after an initial '+' is invalid, so the next token is read
63+
# without skipping it. ``None`` is used when the iterator is exhausted.
64+
token = next(tokens, None)
65+
if token is not None and token.type == 'ident':
6466
ident = token.lower_value
6567
if ident == 'n':
6668
return parse_b(tokens, 1)
@@ -87,7 +89,7 @@ def parse_b(tokens, a):
8789

8890
def parse_signless_b(tokens, a, b_sign):
8991
token = _next_significant(tokens)
90-
if (token.type == 'number' and token.is_integer and
92+
if (token is not None and token.type == 'number' and token.is_integer and
9193
token.representation[0] not in '-+'):
9294
return parse_end(tokens, a, b_sign * token.int_value)
9395

0 commit comments

Comments
 (0)