Skip to content

Commit 9ec2242

Browse files
committed
Add tests and errors handling.
1 parent 053f266 commit 9ec2242

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

cssselect/parser.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,21 @@ def parse_simple_selector(stream, inside_negation=False):
401401
selector_start = len(stream.used)
402402
peek = stream.peek()
403403
if peek.type == 'IDENT' or peek == ('DELIM', '*') or peek == ('DELIM', '<'):
404-
if peek.type == 'IDENT' or peek == ('DELIM', '<'):
404+
if peek.type == 'IDENT':
405405
namespace = stream.next().value
406+
elif peek == ('DELIM', '<'):
407+
if not (len(stream.used) == 0 or
408+
(len(stream.used) == 1 and stream.used[0].type == 'S')):
409+
raise SelectorSyntaxError(
410+
'Got immediate child pseudo-element "<>" not at the start of a selector'
411+
)
412+
namespace = stream.next().value
413+
stream.skip_whitespace()
414+
peek = stream.peek()
415+
if not peek == ('DELIM', '>'):
416+
raise SelectorSyntaxError(
417+
'Got incomplete immediate child pseudo-element "<>" (no ">")'
418+
)
406419
else:
407420
stream.next()
408421
namespace = None

tests/test_cssselect.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class TestCssselect(unittest.TestCase):
4242
def test_tokenizer(self):
4343
tokens = [
4444
_unicode(item) for item in tokenize(
45-
u(r'E\ é > f [a~="y\"x"]:nth(/* fu /]* */-3.7)'))]
45+
u(r'E\ é > f [a~="y\"x"]:nth(/* fu /]* */-3.7)<'))]
4646
assert tokens == [
4747
u("<IDENT 'E é' at 0>"),
4848
"<S ' ' at 4>",
@@ -61,7 +61,8 @@ def test_tokenizer(self):
6161
"<DELIM '(' at 24>",
6262
"<NUMBER '-3.7' at 37>",
6363
"<DELIM ')' at 41>",
64-
"<EOF at 42>",
64+
"<DELIM '<' at 42>",
65+
"<EOF at 43>",
6566
]
6667

6768
def test_parser(self):
@@ -146,6 +147,18 @@ def parse_many(first, *others):
146147
'Negation[Element[div]:not(Class[Element[div].foo])]']
147148
assert parse_many('td ~ th') == [
148149
'CombinedSelector[Element[td] ~ Element[th]]']
150+
# assert parse_many('<') == ['Element[<]']
151+
# assert parse_many('<> foo') == [
152+
# 'CombinedSelector[Element[<] > Element[foo]]'
153+
# ]
154+
# assert parse_many('<> foo bar > div') == [
155+
# 'CombinedSelector[CombinedSelector[CombinedSelector[Element[<] > Element[foo]] '
156+
# '<followed> Element[bar]] > Element[div]]'
157+
# ]
158+
# assert parse_many('<> #foo #bar') == [
159+
# 'CombinedSelector[CombinedSelector[Element[<] > Hash[Element[*]#foo]] '
160+
# '<followed> Hash[Element[*]#bar]]'
161+
# ]
149162

150163
def test_pseudo_elements(self):
151164
def parse_pseudo(css):
@@ -310,6 +323,12 @@ def get_error(css):
310323
"Got pseudo-element ::before inside :not() at 12")
311324
assert get_error(':not(:not(a))') == (
312325
"Got nested :not()")
326+
assert get_error('<> div <> header') == (
327+
'Got immediate child pseudo-element "<>" not at the start of a selector'
328+
)
329+
assert get_error('< div p') == (
330+
'Got incomplete immediate child pseudo-element "<>" (no ">")')
331+
assert get_error('> div p') == ("Expected selector, got <DELIM '>' at 0>")
313332

314333
def test_translation(self):
315334
def xpath(css):
@@ -483,6 +502,8 @@ def test_quoting(self):
483502
'''descendant-or-self::*[@aval = '"']''')
484503
assert css_to_xpath('*[aval=\'"""\']') == (
485504
'''descendant-or-self::*[@aval = '"""']''')
505+
assert css_to_xpath('<> div[dataimg="<testmessage>"]') == (
506+
"child::div[@dataimg = '<testmessage>']")
486507

487508
def test_unicode_escapes(self):
488509
# \22 == '"' \20 == ' '
@@ -672,6 +693,11 @@ def pcss(main, *selectors, **kwargs):
672693
assert pcss(':lang("EN")', '*:lang(en-US)', html_only=True) == [
673694
'second-li', 'li-div']
674695
assert pcss(':lang("e")', html_only=True) == []
696+
assert pcss('<> div') == []
697+
assert pcss('<> body') == ['nil']
698+
assert pcss('<> body > div') == ['outer-div', 'foobar-div']
699+
assert pcss('<> head') == ['nil']
700+
assert pcss('<> html') == []
675701

676702
# --- nth-* and nth-last-* -------------------------------------
677703

@@ -853,6 +879,7 @@ def count(selector):
853879
assert count('div[class|=dialog]') == 50 # ? Seems right
854880
assert count('div[class!=madeup]') == 243 # ? Seems right
855881
assert count('div[class~=dialog]') == 51 # ? Seems right
882+
assert count('<> div') == 1
856883

857884
XMLLANG_IDS = '''
858885
<test>

0 commit comments

Comments
 (0)