Skip to content

Commit 0612c65

Browse files
committed
Test rejection of selectors with unmatched parentheses
Also reject selectors with unclosed parentheses.
1 parent 4fa98e3 commit 0612c65

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

src/RuleSet/DeclarationBlock.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
8888
break;
8989
}
9090
} while (!\in_array($nextCharacter, ['{', '}'], true) || \is_string($stringWrapperCharacter));
91+
if ($functionNestingLevel !== 0) {
92+
throw new UnexpectedTokenException(')', $nextCharacter);
93+
}
9194
$selectors[] = \implode('', $selectorParts); // add final or only selector
9295
$result->setSelectors($selectors, $list);
9396
if ($parserState->comes('{')) {

tests/Unit/RuleSet/DeclarationBlockTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,40 @@ public function parsesTwoCommaSeparatedSelectors(string $firstSelector, string $
115115
self::assertSame([$firstSelector, $secondSelector], self::getSelectorsAsStrings($subject));
116116
}
117117

118+
/**
119+
* @return array<non-empty-string, array{0: non-empty-string}>
120+
*/
121+
public static function provideInvalidSelector(): array
122+
{
123+
// TODO: the `parse` method consumes the first character without inspection,
124+
// so the 'lone' test strings are prefixed with a space.
125+
return [
126+
'lone `(`' => [' ('],
127+
'lone `)`' => [' )'],
128+
'unclosed `(`' => [':not(#your-mug'],
129+
'extra `)`' => [':not(#your-mug))'],
130+
];
131+
}
132+
133+
/**
134+
* @test
135+
*
136+
* @param non-empty-string $selector
137+
*
138+
* @dataProvider provideInvalidSelector
139+
*/
140+
public function parseSkipsBlockWithInvalidSelector(string $selector): void
141+
{
142+
static $nextCss = ' .next {}';
143+
$css = $selector . ' {}' . $nextCss;
144+
$parserState = new ParserState($css, Settings::create());
145+
146+
$subject = DeclarationBlock::parse($parserState);
147+
148+
self::assertNull($subject);
149+
self::assertTrue($parserState->comes($nextCss));
150+
}
151+
118152
/**
119153
* @return array<string>
120154
*/

0 commit comments

Comments
 (0)