Skip to content

Commit fe783d5

Browse files
committed
Add selector specificity tests pinning cascade ordering
Lock in the CSS 2.1 specificity the internal Selector AST computes (id 100, class / attribute / pseudo 10, element 1, universal 0; combinators sum, selector lists report the maximum). Cascade order depends on these values, so the replacement parser planned for Phase 3 step 2 must reproduce them.
1 parent 23e2cf7 commit fe783d5

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

  • tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core

tests/org.eclipse.e4.ui.tests.css.core/src/org/eclipse/e4/ui/tests/css/core/CSSEngineTest.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*******************************************************************************/
1717
package org.eclipse.e4.ui.tests.css.core;
1818

19+
import static org.junit.jupiter.api.Assertions.assertEquals;
1920
import static org.junit.jupiter.api.Assertions.assertFalse;
2021
import static org.junit.jupiter.api.Assertions.assertTrue;
2122

@@ -274,6 +275,62 @@ void testTagNameCaseSensitivity() throws Exception {
274275
assertFalse(engine.matches(lower, capitalElement, null));
275276
}
276277

278+
// --- Selector specificity (cascade ordering depends on this) ---
279+
280+
@Test
281+
void testSimpleSelectorSpecificity() throws Exception {
282+
TestCSSEngine engine = new TestCSSEngine();
283+
assertEquals(0, parse(engine, "*").specificity());
284+
assertEquals(1, parse(engine, "Button").specificity());
285+
assertEquals(10, parse(engine, ".primary").specificity());
286+
assertEquals(100, parse(engine, "#go").specificity());
287+
}
288+
289+
@Test
290+
void testAttributeAndPseudoSpecificity() throws Exception {
291+
TestCSSEngine engine = new TestCSSEngine();
292+
// Attribute and pseudo-class selectors weigh the same as a class.
293+
assertEquals(11, parse(engine, "Button[style]").specificity());
294+
assertEquals(11, parse(engine, "Button[style~='SWT.CHECK']").specificity());
295+
assertEquals(11, parse(engine, "Button:selected").specificity());
296+
}
297+
298+
@Test
299+
void testCompoundSelectorSpecificitySums() throws Exception {
300+
TestCSSEngine engine = new TestCSSEngine();
301+
// Button + .primary + #go = 1 + 10 + 100.
302+
assertEquals(111, parse(engine, "Button.primary#go").specificity());
303+
}
304+
305+
@Test
306+
void testCombinatorSpecificitySums() throws Exception {
307+
TestCSSEngine engine = new TestCSSEngine();
308+
// Combinators contribute nothing themselves; the operands sum.
309+
assertEquals(2, parse(engine, "Composite Button").specificity());
310+
assertEquals(2, parse(engine, "Composite > Button").specificity());
311+
assertEquals(11, parse(engine, "Composite .primary").specificity());
312+
}
313+
314+
@Test
315+
void testSelectorListSpecificityIsMax() throws Exception {
316+
TestCSSEngine engine = new TestCSSEngine();
317+
// A list reports the highest specificity among its alternatives.
318+
assertEquals(100, engine.parseSelectors("Button, .primary, #go").specificity());
319+
assertEquals(10, engine.parseSelectors("Button, .primary").specificity());
320+
}
321+
322+
@Test
323+
void testSpecificityOrderingIdBeatsClassBeatsType() throws Exception {
324+
TestCSSEngine engine = new TestCSSEngine();
325+
int universal = parse(engine, "*").specificity();
326+
int type = parse(engine, "Button").specificity();
327+
int clazz = parse(engine, ".primary").specificity();
328+
int id = parse(engine, "#go").specificity();
329+
assertTrue(universal < type, "universal must rank below a type selector");
330+
assertTrue(type < clazz, "a type selector must rank below a class selector");
331+
assertTrue(clazz < id, "a class selector must rank below an id selector");
332+
}
333+
277334
private static boolean matchesAny(CSSEngine engine, Selectors.SelectorList list, Element element) {
278335
for (Selector selector : list.alternatives()) {
279336
if (engine.matches(selector, element, null)) {

0 commit comments

Comments
 (0)