`,
`div :matchesOwn(^\d+$)`,
[]string{
`
01234567 89
`,
`
567 `,
},
},
{
`
`,
`[href#=(fina)]:not([href#=(\/\/[^\/]+untrusted)])`,
[]string{
`
`,
`
`,
},
},
{
`
`,
`[href#=(^https:\/\/[^\/]*\/?news)]`,
[]string{
`
`,
},
},
{
`
`,
`:input`,
[]string{
`
`,
`
`,
`
Canada
United States
`,
`
`,
`
Sign up `,
},
},
{
``,
":root",
[]string{
"",
},
},
{
``,
"*:root",
[]string{
"",
},
},
{
``,
"html:nth-child(1)",
[]string{
"",
},
},
{
``,
"*:root:first-child",
[]string{
``,
},
},
{
``,
"*:root:nth-child(1)",
[]string{
``,
},
},
{
`
`,
"a:not(:root)",
[]string{
`
`,
},
},
{
`
`,
"body > *:nth-child(3n+2)",
[]string{
"
",
"
",
},
},
{
`
`,
"input:disabled",
[]string{
`
`,
},
},
{
`
`,
":disabled",
[]string{
`
`,
},
},
{
`
`,
":enabled",
[]string{
`
`,
},
},
{
`
`,
"div.class1, div.class2",
[]string{
`
`,
`
`,
},
},
}
func setup(selector, testHTML string) (Selector, *html.Node, error) {
s, err := Compile(selector)
if err != nil {
return nil, nil, fmt.Errorf("error compiling %q: %s", selector, err)
}
doc, err := html.Parse(strings.NewReader(testHTML))
if err != nil {
return nil, nil, fmt.Errorf("error parsing %q: %s", testHTML, err)
}
return s, doc, nil
}
func TestSelectors(t *testing.T) {
for _, test := range selectorTests {
s, doc, err := setup(test.selector, test.HTML)
if err != nil {
t.Error(err)
continue
}
matches := s.MatchAll(doc)
if len(matches) != len(test.results) {
t.Errorf("selector %s wanted %d elements, got %d instead", test.selector, len(test.results), len(matches))
continue
}
for i, m := range matches {
got := nodeString(m)
if got != test.results[i] {
t.Errorf("selector %s wanted %s, got %s instead", test.selector, test.results[i], got)
}
}
firstMatch := s.MatchFirst(doc)
if len(test.results) == 0 {
if firstMatch != nil {
t.Errorf("MatchFirst: selector %s want nil, got %s", test.selector, nodeString(firstMatch))
}
} else {
got := nodeString(firstMatch)
if got != test.results[0] {
t.Errorf("MatchFirst: selector %s want %s, got %s", test.selector, test.results[0], got)
}
}
}
}
func setupMatcher(selector, testHTML string) (Matcher, *html.Node, error) {
s, err := ParseGroup(selector)
if err != nil {
return nil, nil, fmt.Errorf("error compiling %q: %s", selector, err)
}
doc, err := html.Parse(strings.NewReader(testHTML))
if err != nil {
return nil, nil, fmt.Errorf("error parsing %q: %s", testHTML, err)
}
return s, doc, nil
}
func TestMatchers(t *testing.T) {
for _, test := range selectorTests {
s, doc, err := setupMatcher(test.selector, test.HTML)
if err != nil {
t.Error(err)
continue
}
matches := QueryAll(doc, s)
if len(matches) != len(test.results) {
t.Errorf("selector %s wanted %d elements, got %d instead", test.selector, len(test.results), len(matches))
continue
}
for i, m := range matches {
got := nodeString(m)
if got != test.results[i] {
t.Errorf("selector %s wanted %s, got %s instead", test.selector, test.results[i], got)
}
}
firstMatch := Query(doc, s)
if len(test.results) == 0 {
if firstMatch != nil {
t.Errorf("Query: selector %s want nil, got %s", test.selector, nodeString(firstMatch))
}
} else {
got := nodeString(firstMatch)
if got != test.results[0] {
t.Errorf("Query: selector %s want %s, got %s", test.selector, test.results[0], got)
}
}
if !reflect.DeepEqual(matches, Selector(s.Match).Filter(matches)) {
t.Fatalf("inconsistent Filter result")
}
}
}
type testPseudo struct {
HTML, selector string
spec Specificity
pseudo string
}
var testsPseudo = []testPseudo{
{
HTML: `
`,
selector: "#s12:not(FOO)::before",
spec: Specificity{1, 0, 2},
pseudo: "before",
},
{
HTML: `
`,
selector: "#s12::first-line",
spec: Specificity{1, 0, 1},
pseudo: "first-line",
},
{
HTML: `
`,
selector: "ol > #s12:first-line",
spec: Specificity{1, 0, 2},
pseudo: "first-line",
},
{
HTML: `
`,
selector: "#s12:not(FOO)::after",
spec: Specificity{1, 0, 2},
pseudo: "after",
},
{
HTML: `
`,
selector: "LI.red.level:before",
spec: Specificity{0, 2, 2},
pseudo: "before",
},
}
func TestPseudoElement(t *testing.T) {
for _, test := range testsPseudo {
s, err := ParseWithPseudoElement(test.selector)
if err != nil {
t.Fatalf("error compiling %q: %s", test.selector, err)
}
if _, err = Parse(test.selector); err == nil {
t.Fatalf("selector %s with pseudo-element should not compile", test.selector)
}
doc, err := html.Parse(strings.NewReader(test.HTML))
if err != nil {
t.Fatalf("error parsing %q: %s", test.HTML, err)
}
body := doc.FirstChild.LastChild
testNode := body.FirstChild.FirstChild.LastChild
if !s.Match(testNode) {
t.Errorf("%s didn't match (html tree : \n %s) \n", test.selector, nodeString(doc))
continue
}
if s.Specificity() != test.spec {
t.Errorf("wrong specificity : expected %v got %v", test.spec, s.Specificity())
}
if s.PseudoElement() != test.pseudo {
t.Errorf("wrong pseudo-element : expected %s got %s", test.pseudo, s.PseudoElement())
}
}
}
type invalidSelector struct {
Name string `json:"name,omitempty"`
Selector string `json:"selector,omitempty"`
}
type validSelector struct {
invalidSelector
Expect []string `json:"expect,omitempty"`
Exclude []string `json:"exclude,omitempty"`
Level int `json:"level,omitempty"`
Xfail bool `json:"xfail,omitempty"`
}
func TestShakespeare(t *testing.T) {
doc := parseReference("test_resources/shakespeare.html")
body := doc.FirstChild.NextSibling.LastChild
assertCount := func(selector string, expected int) {
sel, err := ParseGroup(selector)
if err != nil {
t.Errorf("invalid selector %s", selector)
}
if l := len(Selector(sel.Match).MatchAll(body)); l != expected {
t.Errorf("%s -> expected %d, got %d", selector, expected, l)
}
}
// Data borrowed from https://github.com/Kozea/cssselect2
assertCount("*", 246)
assertCount("div:only-child", 22) // ?
assertCount("div:nth-child(even)", 106)
assertCount("div:nth-child(2n)", 106)
assertCount("div:nth-child(odd)", 137)
assertCount("div:nth-child(2n+1)", 137)
assertCount("div:nth-child(n)", 243)
assertCount("div:last-child", 53)
assertCount("div:first-child", 51)
assertCount("div > div", 242)
assertCount("div + div", 190)
assertCount("div ~ div", 190)
assertCount("body", 1)
assertCount("body div", 243)
assertCount("div", 243)
assertCount("div div", 242)
assertCount("div div div", 241)
assertCount("div, div, div", 243)
assertCount("div, a, span", 243)
assertCount(".dialog", 51)
assertCount("div.dialog", 51)
assertCount("div .dialog", 51)
assertCount("div.character, div.dialog", 99)
assertCount("div.direction.dialog", 0)
assertCount("div.dialog.direction", 0)
assertCount("div.dialog.scene", 1)
assertCount("div.scene.scene", 1)
assertCount("div.scene .scene", 0)
assertCount("div.direction .dialog ", 0)
assertCount("div .dialog .direction", 4)
assertCount("div.dialog .dialog .direction", 4)
assertCount("#speech5", 1)
assertCount("div#speech5", 1)
assertCount("div #speech5", 1)
assertCount("div.scene div.dialog", 49)
assertCount("div#scene1 div.dialog div", 142)
assertCount("#scene1 #speech1", 1)
assertCount("div[class]", 103)
assertCount("div[class=dialog]", 50)
assertCount("div[class^=dia]", 51)
assertCount("div[class$=log]", 50)
assertCount("div[class*=sce]", 1)
assertCount("div[class|=dialog]", 50)
assertCount("div[class~=dialog]", 51)
}
cascadia-1.3.3/serialize.go 0000664 0000000 0000000 00000006641 14731063146 0015600 0 ustar 00root root 0000000 0000000 package cascadia
import (
"fmt"
"strconv"
"strings"
)
// implements the reverse operation Sel -> string
var specialCharReplacer *strings.Replacer
func init() {
var pairs []string
for _, s := range ",!\"#$%&'()*+ -./:;<=>?@[\\]^`{|}~" {
pairs = append(pairs, string(s), "\\"+string(s))
}
specialCharReplacer = strings.NewReplacer(pairs...)
}
// espace special CSS char
func escape(s string) string { return specialCharReplacer.Replace(s) }
func (c tagSelector) String() string {
return c.tag
}
func (c idSelector) String() string {
return "#" + escape(c.id)
}
func (c classSelector) String() string {
return "." + escape(c.class)
}
func (c attrSelector) String() string {
val := c.val
if c.operation == "#=" {
val = c.regexp.String()
} else if c.operation != "" {
val = fmt.Sprintf(`"%s"`, val)
}
ignoreCase := ""
if c.insensitive {
ignoreCase = " i"
}
return fmt.Sprintf(`[%s%s%s%s]`, c.key, c.operation, val, ignoreCase)
}
func (c relativePseudoClassSelector) String() string {
return fmt.Sprintf(":%s(%s)", c.name, c.match.String())
}
func (c containsPseudoClassSelector) String() string {
s := "contains"
if c.own {
s += "Own"
}
return fmt.Sprintf(`:%s("%s")`, s, c.value)
}
func (c regexpPseudoClassSelector) String() string {
s := "matches"
if c.own {
s += "Own"
}
return fmt.Sprintf(":%s(%s)", s, c.regexp.String())
}
func (c nthPseudoClassSelector) String() string {
if c.a == 0 && c.b == 1 { // special cases
s := ":first-"
if c.last {
s = ":last-"
}
if c.ofType {
s += "of-type"
} else {
s += "child"
}
return s
}
var name string
switch [2]bool{c.last, c.ofType} {
case [2]bool{true, true}:
name = "nth-last-of-type"
case [2]bool{true, false}:
name = "nth-last-child"
case [2]bool{false, true}:
name = "nth-of-type"
case [2]bool{false, false}:
name = "nth-child"
}
s := fmt.Sprintf("+%d", c.b)
if c.b < 0 { // avoid +-8 invalid syntax
s = strconv.Itoa(c.b)
}
return fmt.Sprintf(":%s(%dn%s)", name, c.a, s)
}
func (c onlyChildPseudoClassSelector) String() string {
if c.ofType {
return ":only-of-type"
}
return ":only-child"
}
func (c inputPseudoClassSelector) String() string {
return ":input"
}
func (c emptyElementPseudoClassSelector) String() string {
return ":empty"
}
func (c rootPseudoClassSelector) String() string {
return ":root"
}
func (c linkPseudoClassSelector) String() string {
return ":link"
}
func (c langPseudoClassSelector) String() string {
return fmt.Sprintf(":lang(%s)", c.lang)
}
func (c neverMatchSelector) String() string {
return c.value
}
func (c enabledPseudoClassSelector) String() string {
return ":enabled"
}
func (c disabledPseudoClassSelector) String() string {
return ":disabled"
}
func (c checkedPseudoClassSelector) String() string {
return ":checked"
}
func (c compoundSelector) String() string {
if len(c.selectors) == 0 && c.pseudoElement == "" {
return "*"
}
chunks := make([]string, len(c.selectors))
for i, sel := range c.selectors {
chunks[i] = sel.String()
}
s := strings.Join(chunks, "")
if c.pseudoElement != "" {
s += "::" + c.pseudoElement
}
return s
}
func (c combinedSelector) String() string {
start := c.first.String()
if c.second != nil {
start += fmt.Sprintf(" %s %s", string(c.combinator), c.second.String())
}
return start
}
func (c SelectorGroup) String() string {
ck := make([]string, len(c))
for i, s := range c {
ck[i] = s.String()
}
return strings.Join(ck, ", ")
}
cascadia-1.3.3/serialize_test.go 0000664 0000000 0000000 00000001572 14731063146 0016635 0 ustar 00root root 0000000 0000000 package cascadia
import (
"reflect"
"testing"
)
func TestSerialize(t *testing.T) {
var testSer []string
for _, test := range selectorTests {
testSer = append(testSer, test.selector)
}
for _, test := range testsPseudo {
testSer = append(testSer, test.selector)
}
for _, test := range loadValidSelectors(t) {
if test.Xfail {
continue
}
testSer = append(testSer, test.Selector)
}
for _, test := range testSer {
s, err := ParseGroupWithPseudoElements(test)
if err != nil {
t.Fatalf("error compiling %q: %s", test, err)
}
serialized := s.String()
s2, err := ParseGroupWithPseudoElements(serialized)
if err != nil {
t.Errorf("error compiling %q: %s %T (original : %s)", serialized, err, s, test)
}
if !reflect.DeepEqual(s, s2) {
t.Errorf("can't retrieve selector from serialized : %s (original : %s, sel : %#v)", serialized, test, s)
}
}
}
cascadia-1.3.3/specificity.go 0000664 0000000 0000000 00000001041 14731063146 0016111 0 ustar 00root root 0000000 0000000 package cascadia
// Specificity is the CSS specificity as defined in
// https://www.w3.org/TR/selectors/#specificity-rules
// with the convention Specificity = [A,B,C].
type Specificity [3]int
// returns `true` if s < other (strictly), false otherwise
func (s Specificity) Less(other Specificity) bool {
for i := range s {
if s[i] < other[i] {
return true
}
if s[i] > other[i] {
return false
}
}
return false
}
func (s Specificity) Add(other Specificity) Specificity {
for i, sp := range other {
s[i] += sp
}
return s
}
cascadia-1.3.3/specificity_test.go 0000664 0000000 0000000 00000006206 14731063146 0017160 0 ustar 00root root 0000000 0000000 package cascadia
import (
"fmt"
"strings"
"testing"
"golang.org/x/net/html"
)
type testSpec struct {
// html, css selector
HTML, selector string
// correct specificity
spec Specificity
}
var testsSpecificity = []testSpec{
{
HTML: `
`,
selector: ":not(em, strong#foo)",
spec: Specificity{1, 0, 1},
},
{
HTML: `
`,
selector: "*",
spec: Specificity{0, 0, 0},
},
{
HTML: `
`,
selector: "ul",
spec: Specificity{0, 0, 1},
},
{
HTML: `
`,
selector: "ul li",
spec: Specificity{0, 0, 2},
},
{
HTML: `
`,
selector: "ul ol+li",
spec: Specificity{0, 0, 3},
},
{
HTML: `
`,
selector: "H1 + *[REL=up] ",
spec: Specificity{0, 1, 1},
},
{
HTML: `
`,
selector: "UL OL LI.red",
spec: Specificity{0, 1, 3},
},
{
HTML: `
`,
selector: "LI.red.level",
spec: Specificity{0, 2, 1},
},
{
HTML: `
`,
selector: "#x34y",
spec: Specificity{1, 0, 0},
},
{
HTML: `
`,
selector: "#s12:not(FOO)",
spec: Specificity{1, 0, 1},
},
{
HTML: `
`,
selector: "#s12:not(FOO)",
spec: Specificity{1, 0, 1},
},
{
HTML: `
`,
selector: "#s12:empty",
spec: Specificity{1, 1, 0},
},
{
HTML: `
`,
selector: "#s12:only-child",
spec: Specificity{1, 1, 0},
},
}
func setupSel(selector, HTML string) (Sel, *html.Node, error) {
s, err := Parse(selector)
if err != nil {
return nil, nil, fmt.Errorf("error compiling %q: %s", selector, err)
}
doc, err := html.Parse(strings.NewReader(HTML))
if err != nil {
return nil, nil, fmt.Errorf("error parsing %q: %s", HTML, err)
}
return s, doc, nil
}
func TestSpecificity(t *testing.T) {
for _, test := range testsSpecificity {
s, doc, err := setupSel(test.selector, test.HTML)
if err != nil {
t.Fatal(err)
}
body := doc.FirstChild.LastChild
testNode := body.FirstChild.FirstChild.LastChild
if !s.Match(testNode) {
t.Errorf("%s didn't match (html tree : \n %s) \n", test.selector, nodeString(doc))
continue
}
gotSpec := s.Specificity()
if gotSpec != test.spec {
t.Errorf("wrong specificity : expected %v, got %v", test.spec, gotSpec)
}
}
}
func TestCompareSpecificity(t *testing.T) {
s1, s2 := Specificity{1, 1, 0}, Specificity{1, 0, 0}
if s1.Less(s2) {
t.Fatal()
}
if s1.Less(s1) {
t.Fatal()
}
}
cascadia-1.3.3/test_resources/ 0000775 0000000 0000000 00000000000 14731063146 0016324 5 ustar 00root root 0000000 0000000 cascadia-1.3.3/test_resources/content.xhtml 0000664 0000000 0000000 00000053435 14731063146 0021066 0 ustar 00root root 0000000 0000000
Selectors-API Test Suite: HTML with Selectors Level 2 using
TestHarness: Test Document
cascadia-1.3.3/test_resources/invalid_selectors.json 0000664 0000000 0000000 00000004436 14731063146 0022737 0 ustar 00root root 0000000 0000000 [
{"name": "Empty String", "selector": ""},
{"name": "Invalid character", "selector": "["},
{"name": "Invalid character", "selector": "]"},
{"name": "Invalid character", "selector": "("},
{"name": "Invalid character", "selector": ")"},
{"name": "Invalid character", "selector": "{"},
{"name": "Invalid character", "selector": "}"},
{"name": "Invalid character", "selector": "<"},
{"name": "Invalid character", "selector": ">"},
{"name": "Invalid character", "selector": ":"},
{"name": "Invalid character", "selector": "::"},
{"name": "Invalid ID", "selector": "#"},
{"name": "Invalid group of selectors", "selector": "div,"},
{"name": "Invalid class", "selector": "."},
{"name": "Invalid class", "selector": ".5cm"},
{"name": "Invalid class", "selector": "..test"},
{"name": "Invalid class", "selector": ".foo..quux"},
{"name": "Invalid class", "selector": ".bar."},
{"name": "Invalid combinator", "selector": "div & address, p"},
{"name": "Invalid combinator", "selector": "div >> address, p"},
{"name": "Invalid combinator", "selector": "div ++ address, p"},
{"name": "Invalid combinator", "selector": "div ~~ address, p"},
{"name": "Invalid [att=value] selector", "selector": "[*=test]"},
{"name": "Invalid [att=value] selector", "selector": "[*|*=test]"},
{"name": "Invalid [att=value] selector", "selector": "[class= space unquoted ]"},
{"name": "Unknown pseudo-class", "selector": "div:example"},
{"name": "Unknown pseudo-class", "selector": ":example"},
{"name": "Unknown pseudo-element", "selector": "div::example", "xfail": true},
{"name": "Unknown pseudo-element", "selector": "::example", "xfail": true},
{"name": "Invalid pseudo-element", "selector": ":::before"},
{"name": "Undeclared namespace", "selector": "ns|div"},
{"name": "Undeclared namespace", "selector": ":not(ns|div)"},
{"name": "Invalid namespace", "selector": "^|div"},
{"name": "Invalid namespace", "selector": "$|div"},
{"name": "Case insensitive, no closing ]", "selector": "[a=a i"}
]
cascadia-1.3.3/test_resources/shakespeare.html 0000664 0000000 0000000 00000041714 14731063146 0021514 0 ustar 00root root 0000000 0000000
As You Like It
by William Shakespeare
ACT I, SCENE III. A room in the palace.
CELIA
Why, cousin! why, Rosalind! Cupid have mercy! not a word?
ROSALIND
Not one to throw at a dog.
CELIA
No, thy words are too precious to be cast away upon
curs; throw some of them at me; come, lame me with reasons.
ROSALIND
CELIA
But is all this for your father?
Then there were two cousins laid up; when the one
should be lamed with reasons and the other mad
without any.
ROSALIND
No, some of it is for my child's father. O, how
full of briers is this working-day world!
CELIA
They are but burs, cousin, thrown upon thee in
holiday foolery: if we walk not in the trodden
paths our very petticoats will catch them.
ROSALIND
I could shake them off my coat: these burs are in my heart.
CELIA
ROSALIND
I would try, if I could cry 'hem' and have him.
CELIA
Come, come, wrestle with thy affections.
ROSALIND
O, they take the part of a better wrestler than myself!
CELIA
O, a good wish upon you! you will try in time, in
despite of a fall. But, turning these jests out of
service, let us talk in good earnest: is it
possible, on such a sudden, you should fall into so
strong a liking with old Sir Rowland's youngest son?
ROSALIND
The duke my father loved his father dearly.
CELIA
Doth it therefore ensue that you should love his son
dearly? By this kind of chase, I should hate him,
for my father hated his father dearly; yet I hate
not Orlando.
ROSALIND
No, faith, hate him not, for my sake.
CELIA
Why should I not? doth he not deserve well?
ROSALIND
Let me love him for that, and do you love him
because I do. Look, here comes the duke.
CELIA
With his eyes full of anger.
Enter DUKE FREDERICK, with Lords
DUKE FREDERICK
Mistress, dispatch you with your safest haste
And get you from our court.
ROSALIND
DUKE FREDERICK
You, cousin
Within these ten days if that thou be'st found
So near our public court as twenty miles,
Thou diest for it.
ROSALIND
I do beseech your grace,
Let me the knowledge of my fault bear with me:
If with myself I hold intelligence
Or have acquaintance with mine own desires,
If that I do not dream or be not frantic,--
As I do trust I am not--then, dear uncle,
Never so much as in a thought unborn
Did I offend your highness.
DUKE FREDERICK
Thus do all traitors:
If their purgation did consist in words,
They are as innocent as grace itself:
Let it suffice thee that I trust thee not.
ROSALIND
Yet your mistrust cannot make me a traitor:
Tell me whereon the likelihood depends.
DUKE FREDERICK
Thou art thy father's daughter; there's enough.
ROSALIND
So was I when your highness took his dukedom;
So was I when your highness banish'd him:
Treason is not inherited, my lord;
Or, if we did derive it from our friends,
What's that to me? my father was no traitor:
Then, good my liege, mistake me not so much
To think my poverty is treacherous.
CELIA
Dear sovereign, hear me speak.
DUKE FREDERICK
Ay, Celia; we stay'd her for your sake,
Else had she with her father ranged along.
CELIA
I did not then entreat to have her stay;
It was your pleasure and your own remorse:
I was too young that time to value her;
But now I know her: if she be a traitor,
Why so am I; we still have slept together,
Rose at an instant, learn'd, play'd, eat together,
And wheresoever we went, like Juno's swans,
Still we went coupled and inseparable.
DUKE FREDERICK
She is too subtle for thee; and her smoothness,
Her very silence and her patience
Speak to the people, and they pity her.
Thou art a fool: she robs thee of thy name;
And thou wilt show more bright and seem more virtuous
When she is gone. Then open not thy lips:
Firm and irrevocable is my doom
Which I have pass'd upon her; she is banish'd.
CELIA
Pronounce that sentence then on me, my liege:
I cannot live out of her company.
DUKE FREDERICK
You are a fool. You, niece, provide yourself:
If you outstay the time, upon mine honour,
And in the greatness of my word, you die.
Exeunt DUKE FREDERICK and Lords
CELIA
O my poor Rosalind, whither wilt thou go?
Wilt thou change fathers? I will give thee mine.
I charge thee, be not thou more grieved than I am.
ROSALIND
CELIA
Thou hast not, cousin;
Prithee be cheerful: know'st thou not, the duke
Hath banish'd me, his daughter?
ROSALIND
CELIA
No, hath not? Rosalind lacks then the love
Which teacheth thee that thou and I am one:
Shall we be sunder'd? shall we part, sweet girl?
No: let my father seek another heir.
Therefore devise with me how we may fly,
Whither to go and what to bear with us;
And do not seek to take your change upon you,
To bear your griefs yourself and leave me out;
For, by this heaven, now at our sorrows pale,
Say what thou canst, I'll go along with thee.
ROSALIND
Why, whither shall we go?
CELIA
To seek my uncle in the forest of Arden.
ROSALIND
Alas, what danger will it be to us,
Maids as we are, to travel forth so far!
Beauty provoketh thieves sooner than gold.
CELIA
I'll put myself in poor and mean attire
And with a kind of umber smirch my face;
The like do you: so shall we pass along
And never stir assailants.
ROSALIND
Were it not better,
Because that I am more than common tall,
That I did suit me all points like a man?
A gallant curtle-axe upon my thigh,
A boar-spear in my hand; and--in my heart
Lie there what hidden woman's fear there will--
We'll have a swashing and a martial outside,
As many other mannish cowards have
That do outface it with their semblances.
CELIA
What shall I call thee when thou art a man?
ROSALIND
I'll have no worse a name than Jove's own page;
And therefore look you call me Ganymede.
But what will you be call'd?
CELIA
Something that hath a reference to my state
No longer Celia, but Aliena.
ROSALIND
But, cousin, what if we assay'd to steal
The clownish fool out of your father's court?
Would he not be a comfort to our travel?
CELIA
He'll go along o'er the wide world with me;
Leave me alone to woo him. Let's away,
And get our jewels and our wealth together,
Devise the fittest time and safest way
To hide us from pursuit that will be made
After my flight. Now go we in content
To liberty and not to banishment.
Exeunt
cascadia-1.3.3/test_resources/valid_selectors.json 0000664 0000000 0000000 00000124762 14731063146 0022415 0 ustar 00root root 0000000 0000000 [
{
"name": "Type selector, matching html element",
"selector": "html",
"expect": [
"html"
],
"exclude": [
"element",
"fragment",
"detached"
],
"level": 1
},
{
"name": "Type selector, matching body element",
"selector": "body",
"expect": [
"body"
],
"exclude": [
"element",
"fragment",
"detached"
],
"level": 1
},
{
"name": "Universal selector, matching all children of element with specified ID",
"selector": "#universal>*",
"expect": [
"universal-p1",
"universal-hr1",
"universal-pre1",
"universal-p2",
"universal-address1"
],
"level": 2
},
{
"name": "Universal selector, matching all grandchildren of element with specified ID",
"selector": "#universal>*>*",
"expect": [
"universal-code1",
"universal-span1",
"universal-a1",
"universal-code2"
],
"level": 2
},
{
"name": "Universal selector, matching all children of empty element with specified ID",
"selector": "#empty>*",
"expect": [],
"level": 2
},
{
"name": "Universal selector, matching all descendants of element with specified ID",
"selector": "#universal *",
"expect": [
"universal-p1",
"universal-code1",
"universal-hr1",
"universal-pre1",
"universal-span1",
"universal-p2",
"universal-a1",
"universal-address1",
"universal-code2",
"universal-a2"
],
"level": 2
},
{
"name": "Attribute presence selector, matching align attribute with value",
"selector": ".attr-presence-div1[align]",
"expect": [
"attr-presence-div1"
],
"level": 2
},
{
"name": "Attribute presence selector, matching align attribute with empty value",
"selector": ".attr-presence-div2[align]",
"expect": [
"attr-presence-div2"
],
"level": 2
},
{
"name": "Attribute presence selector, matching title attribute, case insensitivity",
"selector": "#attr-presence [TiTlE]",
"expect": [
"attr-presence-a1",
"attr-presence-span1"
],
"exclude": [
"xhtml"
],
"level": 2
},
{
"name": "Attribute presence selector, matching custom data-* attribute",
"selector": "[data-attr-presence]",
"expect": [
"attr-presence-pre1",
"attr-presence-blockquote1"
],
"level": 2
},
{
"name": "Attribute presence selector, not matching attribute with similar name",
"selector": ".attr-presence-div3[align], .attr-presence-div4[align]",
"expect": [],
"level": 2
},
{
"name": "Attribute presence selector, matching attribute with non-ASCII characters",
"selector": "ul[data-中文]",
"expect": [
"attr-presence-ul1"
],
"level": 2
},
{
"name": "Attribute presence selector, not matching default option without selected attribute",
"selector": "#attr-presence-select1 option[selected]",
"expect": [],
"level": 2
},
{
"name": "Attribute presence selector, matching option with selected attribute",
"selector": "#attr-presence-select2 option[selected]",
"expect": [
"attr-presence-select2-option4"
],
"level": 2
},
{
"name": "Attribute presence selector, matching multiple options with selected attributes",
"selector": "#attr-presence-select3 option[selected]",
"expect": [
"attr-presence-select3-option2",
"attr-presence-select3-option3"
],
"level": 2
},
{
"name": "Attribute value selector, matching align attribute with value",
"selector": "#attr-value [align=\"center\"]",
"expect": [
"attr-value-div1"
],
"level": 2
},
{
"name": "Attribute value selector, matching align attribute with empty value",
"selector": "#attr-value [align=\"\"]",
"expect": [
"attr-value-div2"
],
"level": 2
},
{
"name": "Attribute value selector, not matching align attribute with partial value",
"selector": "#attr-value [align=\"c\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute value selector, not matching align attribute with incorrect value",
"selector": "#attr-value [align=\"centera\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute value selector, matching custom data-* attribute with unicode escaped value",
"selector": "[data-attr-value=\"\\e9\"]",
"expect": [
"attr-value-div3"
],
"level": 2
},
{
"name": "Attribute value selector, matching custom data-* attribute with escaped character",
"selector": "[data-attr-value_foo=\"\\e9\"]",
"expect": [
"attr-value-div4"
],
"level": 2
},
{
"name": "Attribute value selector with single-quoted value, matching multiple inputs with type attributes",
"selector": "#attr-value input[type='hidden'],#attr-value input[type='radio']",
"expect": [
"attr-value-input3",
"attr-value-input4",
"attr-value-input6",
"attr-value-input8",
"attr-value-input9"
],
"level": 2
},
{
"name": "Attribute value selector with double-quoted value, matching multiple inputs with type attributes",
"selector": "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']",
"expect": [
"attr-value-input3",
"attr-value-input4",
"attr-value-input6",
"attr-value-input8",
"attr-value-input9"
],
"level": 2
},
{
"name": "Attribute value selector with unquoted value, matching multiple inputs with type attributes",
"selector": "#attr-value input[type=hidden],#attr-value input[type=radio]",
"expect": [
"attr-value-input3",
"attr-value-input4",
"attr-value-input6",
"attr-value-input8",
"attr-value-input9"
],
"level": 2
},
{
"name": "Attribute value selector, matching attribute with value using non-ASCII characters",
"selector": "[data-attr-value=中文]",
"expect": [
"attr-value-div5"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, matching class attribute with value",
"selector": "#attr-whitespace [class~=\"div1\"]",
"expect": [
"attr-whitespace-div1"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, not matching class attribute with empty value",
"selector": "#attr-whitespace [class~=\"\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, not matching class attribute with partial value",
"selector": "[data-attr-whitespace~=\"div\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value",
"selector": "[data-attr-whitespace~=\"\\0000e9\"]",
"expect": [
"attr-whitespace-div4"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character",
"selector": "[data-attr-whitespace_foo~=\"\\e9\"]",
"expect": [
"attr-whitespace-div5"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes",
"selector": "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']",
"expect": [
"attr-whitespace-a1",
"attr-whitespace-a2",
"attr-whitespace-a3",
"attr-whitespace-a5",
"attr-whitespace-a7"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes",
"selector": "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']",
"expect": [
"attr-whitespace-a1",
"attr-whitespace-a2",
"attr-whitespace-a3",
"attr-whitespace-a5",
"attr-whitespace-a7"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes",
"selector": "#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]",
"expect": [
"attr-whitespace-a1",
"attr-whitespace-a2",
"attr-whitespace-a3",
"attr-whitespace-a5",
"attr-whitespace-a7"
],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector with double-quoted value, not matching value with space",
"selector": "#attr-whitespace a[rel~=\"book mark\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters",
"selector": "#attr-whitespace [title~=中文]",
"expect": [
"attr-whitespace-p1"
],
"level": 2
},
{
"name": "Attribute hyphen-separated list selector, not matching unspecified lang attribute",
"selector": "#attr-hyphen-div1[lang|=\"en\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute hyphen-separated list selector, matching lang attribute with exact value",
"selector": "#attr-hyphen-div2[lang|=\"fr\"]",
"expect": [
"attr-hyphen-div2"
],
"level": 2
},
{
"name": "Attribute hyphen-separated list selector, matching lang attribute with partial value",
"selector": "#attr-hyphen-div3[lang|=\"en\"]",
"expect": [
"attr-hyphen-div3"
],
"level": 2
},
{
"name": "Attribute hyphen-separated list selector, not matching incorrect value",
"selector": "#attr-hyphen-div4[lang|=\"es-AR\"]",
"expect": [],
"level": 2
},
{
"name": "Attribute begins with selector, matching href attributes beginning with specified substring",
"selector": "#attr-begins a[href^=\"http://www\"]",
"expect": [
"attr-begins-a1",
"attr-begins-a3"
],
"level": 3
},
{
"name": "Attribute begins with selector, matching lang attributes beginning with specified substring, ",
"selector": "#attr-begins [lang^=\"en-\"]",
"expect": [
"attr-begins-div2",
"attr-begins-div4"
],
"level": 3
},
{
"name": "Attribute begins with selector, not matching class attribute not beginning with specified substring",
"selector": "#attr-begins [class^=apple]",
"expect": [],
"level": 3
},
{
"name": "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring",
"selector": "#attr-begins [class^=' apple']",
"expect": [
"attr-begins-p1"
],
"level": 3
},
{
"name": "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring",
"selector": "#attr-begins [class^=\" apple\"]",
"expect": [
"attr-begins-p1"
],
"level": 3
},
{
"name": "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring",
"selector": "#attr-begins [class^= apple]",
"expect": [],
"level": 3
},
{
"name": "Attribute ends with selector, matching href attributes ending with specified substring",
"selector": "#attr-ends a[href$=\".org\"]",
"expect": [
"attr-ends-a1",
"attr-ends-a3"
],
"level": 3
},
{
"name": "Attribute ends with selector, matching lang attributes ending with specified substring, ",
"selector": "#attr-ends [lang$=\"-CH\"]",
"expect": [
"attr-ends-div2",
"attr-ends-div4"
],
"level": 3
},
{
"name": "Attribute ends with selector, not matching class attribute not ending with specified substring",
"selector": "#attr-ends [class$=apple]",
"expect": [],
"level": 3
},
{
"name": "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring",
"selector": "#attr-ends [class$='apple ']",
"expect": [
"attr-ends-p1"
],
"level": 3
},
{
"name": "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring",
"selector": "#attr-ends [class$=\"apple \"]",
"expect": [
"attr-ends-p1"
],
"level": 3
},
{
"name": "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring",
"selector": "#attr-ends [class$=apple ]",
"expect": [],
"level": 3
},
{
"name": "Attribute contains selector, matching href attributes beginning with specified substring",
"selector": "#attr-contains a[href*=\"http://www\"]",
"expect": [
"attr-contains-a1",
"attr-contains-a3"
],
"level": 3
},
{
"name": "Attribute contains selector, matching href attributes ending with specified substring",
"selector": "#attr-contains a[href*=\".org\"]",
"expect": [
"attr-contains-a1",
"attr-contains-a2"
],
"level": 3
},
{
"name": "Attribute contains selector, matching href attributes containing specified substring",
"selector": "#attr-contains a[href*=\".example.\"]",
"expect": [
"attr-contains-a1",
"attr-contains-a3"
],
"level": 3
},
{
"name": "Attribute contains selector, matching lang attributes beginning with specified substring, ",
"selector": "#attr-contains [lang*=\"en-\"]",
"expect": [
"attr-contains-div2",
"attr-contains-div6"
],
"level": 3
},
{
"name": "Attribute contains selector, matching lang attributes ending with specified substring, ",
"selector": "#attr-contains [lang*=\"-CH\"]",
"expect": [
"attr-contains-div3",
"attr-contains-div5"
],
"level": 3
},
{
"name": "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring",
"selector": "#attr-contains [class*=' apple']",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring",
"selector": "#attr-contains [class*='orange ']",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with single-quoted value, matching class attribute containing specified substring",
"selector": "#attr-contains [class*='ple banana ora']",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring",
"selector": "#attr-contains [class*=\" apple\"]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring",
"selector": "#attr-contains [class*=\"orange \"]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with double-quoted value, matching class attribute containing specified substring",
"selector": "#attr-contains [class*=\"ple banana ora\"]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring",
"selector": "#attr-contains [class*= apple]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with unquoted value, matching class attribute ending with specified substring",
"selector": "#attr-contains [class*=orange ]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": "Attribute contains selector with unquoted value, matching class attribute containing specified substring",
"selector": "#attr-contains [class*= banana ]",
"expect": [
"attr-contains-p1"
],
"level": 3
},
{
"name": ":root pseudo-class selector, matching document root element",
"selector": ":root",
"expect": [
"html"
],
"exclude": [
"element",
"fragment",
"detached"
],
"level": 3
},
{
"name": ":nth-child selector, matching the third child element",
"selector": "#pseudo-nth-table1 :nth-child(3)",
"expect": [
"pseudo-nth-td3",
"pseudo-nth-td9",
"pseudo-nth-tr3",
"pseudo-nth-td15"
],
"level": 3
},
{
"name": ":nth-child selector, matching every third child element",
"selector": "#pseudo-nth li:nth-child(3n)",
"expect": [
"pseudo-nth-li3",
"pseudo-nth-li6",
"pseudo-nth-li9",
"pseudo-nth-li12"
],
"level": 3
},
{
"name": ":nth-child selector, matching every second child element, starting from the fourth",
"selector": "#pseudo-nth li:nth-child(2n+4)",
"expect": [
"pseudo-nth-li4",
"pseudo-nth-li6",
"pseudo-nth-li8",
"pseudo-nth-li10",
"pseudo-nth-li12"
],
"level": 3
},
{
"name": ":nth-child selector, matching every fourth child element, starting from the third",
"selector": "#pseudo-nth-p1 :nth-child(4n-1)",
"expect": [
"pseudo-nth-em2",
"pseudo-nth-span3"
],
"level": 3
},
{
"name": ":nth-last-child selector, matching the third last child element",
"selector": "#pseudo-nth-table1 :nth-last-child(3)",
"expect": [
"pseudo-nth-tr1",
"pseudo-nth-td4",
"pseudo-nth-td10",
"pseudo-nth-td16"
],
"level": 3
},
{
"name": ":nth-last-child selector, matching every third child element from the end",
"selector": "#pseudo-nth li:nth-last-child(3n)",
"expect": [
"pseudo-nth-li1",
"pseudo-nth-li4",
"pseudo-nth-li7",
"pseudo-nth-li10"
],
"level": 3
},
{
"name": ":nth-last-child selector, matching every second child element from the end, starting from the fourth last",
"selector": "#pseudo-nth li:nth-last-child(2n+4)",
"expect": [
"pseudo-nth-li1",
"pseudo-nth-li3",
"pseudo-nth-li5",
"pseudo-nth-li7",
"pseudo-nth-li9"
],
"level": 3
},
{
"name": ":nth-last-child selector, matching every fourth element from the end, starting from the third last",
"selector": "#pseudo-nth-p1 :nth-last-child(4n-1)",
"expect": [
"pseudo-nth-span2",
"pseudo-nth-span4"
],
"level": 3
},
{
"name": ":nth-of-type selector, matching the third em element",
"selector": "#pseudo-nth-p1 em:nth-of-type(3)",
"expect": [
"pseudo-nth-em3"
],
"level": 3
},
{
"name": ":nth-of-type selector, matching every second element of their type",
"selector": "#pseudo-nth-p1 :nth-of-type(2n)",
"expect": [
"pseudo-nth-em2",
"pseudo-nth-span2",
"pseudo-nth-span4",
"pseudo-nth-strong2",
"pseudo-nth-em4"
],
"level": 3
},
{
"name": ":nth-of-type selector, matching every second elemetn of their type, starting from the first",
"selector": "#pseudo-nth-p1 span:nth-of-type(2n-1)",
"expect": [
"pseudo-nth-span1",
"pseudo-nth-span3"
],
"level": 3
},
{
"name": ":nth-last-of-type selector, matching the thrid last em element",
"selector": "#pseudo-nth-p1 em:nth-last-of-type(3)",
"expect": [
"pseudo-nth-em2"
],
"level": 3
},
{
"name": ":nth-last-of-type selector, matching every second last element of their type",
"selector": "#pseudo-nth-p1 :nth-last-of-type(2n)",
"expect": [
"pseudo-nth-span1",
"pseudo-nth-em1",
"pseudo-nth-strong1",
"pseudo-nth-em3",
"pseudo-nth-span3"
],
"level": 3
},
{
"name": ":nth-last-of-type selector, matching every second last element of their type, starting from the last",
"selector": "#pseudo-nth-p1 span:nth-last-of-type(2n-1)",
"expect": [
"pseudo-nth-span2",
"pseudo-nth-span4"
],
"level": 3
},
{
"name": ":first-of-type selector, matching the first em element",
"selector": "#pseudo-nth-p1 em:first-of-type",
"expect": [
"pseudo-nth-em1"
],
"level": 3
},
{
"name": ":first-of-type selector, matching the first of every type of element",
"selector": "#pseudo-nth-p1 :first-of-type",
"expect": [
"pseudo-nth-span1",
"pseudo-nth-em1",
"pseudo-nth-strong1"
],
"level": 3
},
{
"name": ":first-of-type selector, matching the first td element in each table row",
"selector": "#pseudo-nth-table1 tr :first-of-type",
"expect": [
"pseudo-nth-td1",
"pseudo-nth-td7",
"pseudo-nth-td13"
],
"level": 3
},
{
"name": ":last-of-type selector, matching the last em elemnet",
"selector": "#pseudo-nth-p1 em:last-of-type",
"expect": [
"pseudo-nth-em4"
],
"level": 3
},
{
"name": ":last-of-type selector, matching the last of every type of element",
"selector": "#pseudo-nth-p1 :last-of-type",
"expect": [
"pseudo-nth-span4",
"pseudo-nth-strong2",
"pseudo-nth-em4"
],
"level": 3
},
{
"name": ":last-of-type selector, matching the last td element in each table row",
"selector": "#pseudo-nth-table1 tr :last-of-type",
"expect": [
"pseudo-nth-td6",
"pseudo-nth-td12",
"pseudo-nth-td18"
],
"level": 3
},
{
"name": ":first-child pseudo-class selector, matching first child div element",
"selector": "#pseudo-first-child div:first-child",
"expect": [
"pseudo-first-child-div1"
],
"level": 2
},
{
"name": ":first-child pseudo-class selector, doesn't match non-first-child elements",
"selector": ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child",
"expect": [],
"level": 2
},
{
"name": ":first-child pseudo-class selector, matching first-child of multiple elements",
"selector": "#pseudo-first-child span:first-child",
"expect": [
"pseudo-first-child-span1",
"pseudo-first-child-span3",
"pseudo-first-child-span5"
],
"level": 2
},
{
"name": ":last-child pseudo-class selector, matching last child div element",
"selector": "#pseudo-last-child div:last-child",
"expect": [
"pseudo-last-child-div3"
],
"level": 3
},
{
"name": ":last-child pseudo-class selector, doesn't match non-last-child elements",
"selector": ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child",
"expect": [],
"level": 3
},
{
"name": ":last-child pseudo-class selector, matching first-child of multiple elements",
"selector": "#pseudo-last-child span:last-child",
"expect": [
"pseudo-last-child-span2",
"pseudo-last-child-span4",
"pseudo-last-child-span6"
],
"level": 3
},
{
"name": ":pseudo-only-child pseudo-class selector, matching all only-child elements",
"selector": "#pseudo-only :only-child",
"expect": [
"pseudo-only-span1"
],
"level": 3
},
{
"name": ":pseudo-only-child pseudo-class selector, matching only-child em elements",
"selector": "#pseudo-only em:only-child",
"expect": [],
"level": 3
},
{
"name": ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type",
"selector": "#pseudo-only :only-of-type",
"expect": [
"pseudo-only-span1",
"pseudo-only-em1"
],
"level": 3
},
{
"name": ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type",
"selector": "#pseudo-only em:only-of-type",
"expect": [
"pseudo-only-em1"
],
"level": 3
},
{
"name": ":empty pseudo-class selector, matching empty p elements",
"selector": "#pseudo-empty p:empty",
"expect": [
"pseudo-empty-p1",
"pseudo-empty-p2",
"pseudo-empty-p3"
],
"level": 3
},
{
"name": ":empty pseudo-class selector, matching all empty elements",
"selector": "#pseudo-empty :empty",
"expect": [
"pseudo-empty-p1",
"pseudo-empty-p2",
"pseudo-empty-p3",
"pseudo-empty-span1"
],
"level": 3
},
{
"name": ":link and :visited pseudo-class selectors, matching a and area elements with href attributes",
"selector": "#pseudo-link :link, #pseudo-link :visited",
"expect": [
"pseudo-link-a1",
"pseudo-link-a2",
"pseudo-link-area1"
],
"level": 1
},
{
"name": ":link and :visited pseudo-class selectors, matching link elements with href attributes",
"selector": "#head :link, #head :visited",
"expect": [
"pseudo-link-link1",
"pseudo-link-link2"
],
"exclude": [
"element",
"fragment",
"detached"
],
"level": 1
},
{
"name": ":target pseudo-class selector, matching the element referenced by the URL fragment identifier",
"selector": ":target",
"xfail": true,
"expect": [
"target"
],
"exclude": [
"fragment",
"detached"
],
"level": 3
},
{
"name": ":lang pseudo-class selector, matching inherited language",
"selector": "#pseudo-lang-div1:lang(en)",
"expect": [
"pseudo-lang-div1"
],
"exclude": [
"detached",
"fragment"
],
"level": 2
},
{
"name": ":lang pseudo-class selector, matching specified language with exact value",
"selector": "#pseudo-lang-div2:lang(fr)",
"expect": [
"pseudo-lang-div2"
],
"level": 2
},
{
"name": ":lang pseudo-class selector, matching specified language with partial value",
"selector": "#pseudo-lang-div3:lang(en)",
"expect": [
"pseudo-lang-div3"
],
"level": 2
},
{
"name": ":lang pseudo-class selector, not matching incorrect language",
"selector": "#pseudo-lang-div4:lang(es-AR)",
"expect": [],
"level": 2
},
{
"name": ":enabled pseudo-class selector, matching all enabled form controls",
"selector": "#pseudo-ui :enabled",
"expect": [
"pseudo-ui-input1",
"pseudo-ui-input2",
"pseudo-ui-input3",
"pseudo-ui-input4",
"pseudo-ui-input5",
"pseudo-ui-input6",
"pseudo-ui-input7",
"pseudo-ui-input8",
"pseudo-ui-input9",
"pseudo-ui-textarea1",
"pseudo-ui-button1"
],
"level": 3
},
{
"name": ":enabled pseudo-class selector, matching all disabled form controls",
"selector": "#pseudo-ui :disabled",
"expect": [
"pseudo-ui-input10",
"pseudo-ui-input11",
"pseudo-ui-input12",
"pseudo-ui-input13",
"pseudo-ui-input14",
"pseudo-ui-input15",
"pseudo-ui-input16",
"pseudo-ui-input17",
"pseudo-ui-input18",
"pseudo-ui-textarea2",
"pseudo-ui-button2"
],
"level": 3
},
{
"name": ":checked pseudo-class selector, matching checked radio buttons and checkboxes",
"selector": "#pseudo-ui :checked",
"expect": [
"pseudo-ui-input4",
"pseudo-ui-input6",
"pseudo-ui-input13",
"pseudo-ui-input15"
],
"level": 3
},
{
"name": ":not pseudo-class selector, matching ",
"selector": "#not>:not(div)",
"expect": [
"not-p1",
"not-p2",
"not-p3"
],
"level": 3
},
{
"name": ":not pseudo-class selector, matching ",
"selector": "#not * :not(:first-child)",
"expect": [
"not-em1",
"not-em2",
"not-em3"
],
"level": 3
},
{
"name": ":not pseudo-class selector, matching nothing",
"selector": ":not(*)",
"expect": [],
"level": 3
},
{
"name": ":not pseudo-class selector, matching nothing",
"selector": ":not(*|*)",
"expect": [],
"level": 3
},
{
"name": ":first-line pseudo-element (one-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element:first-line",
"expect": [],
"level": 2
},
{
"name": "::first-line pseudo-element (two-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element::first-line",
"expect": [],
"level": 3
},
{
"name": ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element:first-letter",
"expect": [],
"level": 2
},
{
"name": "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element::first-letter",
"expect": [],
"level": 3
},
{
"name": ":before pseudo-element (one-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element:before",
"expect": [],
"level": 2
},
{
"name": "::before pseudo-element (two-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element::before",
"expect": [],
"level": 3
},
{
"name": ":after pseudo-element (one-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element:after",
"expect": [],
"level": 2
},
{
"name": "::after pseudo-element (two-colon syntax) selector, not matching any elements",
"selector": "#pseudo-element::after",
"expect": [],
"level": 3
},
{
"name": "Class selector, matching element with specified class",
"selector": ".class-p",
"expect": [
"class-p1",
"class-p2",
"class-p3"
],
"level": 1
},
{
"name": "Class selector, chained, matching only elements with all specified classes",
"selector": "#class .apple.orange.banana",
"expect": [
"class-div1",
"class-div2",
"class-p4",
"class-div3",
"class-p6",
"class-div4"
],
"level": 1
},
{
"name": "Class Selector, chained, with type selector",
"selector": "div.apple.banana.orange",
"expect": [
"class-div1",
"class-div2",
"class-div3",
"class-div4"
],
"level": 1
},
{
"name": "Class selector, matching element with class value using non-ASCII characters",
"selector": ".台北Táiběi",
"expect": [
"class-span1"
],
"level": 1
},
{
"name": "Class selector, matching multiple elements with class value using non-ASCII characters",
"selector": ".台北",
"expect": [
"class-span1",
"class-span2"
],
"level": 1
},
{
"name": "Class selector, chained, matching element with multiple class values using non-ASCII characters",
"selector": ".台北Táiběi.台北",
"expect": [
"class-span1"
],
"level": 1
},
{
"name": "Class selector, matching element with class with escaped character",
"selector": ".foo\\:bar",
"expect": [
"class-span3"
],
"level": 1
},
{
"name": "Class selector, matching element with class with escaped character",
"selector": ".test\\.foo\\[5\\]bar",
"expect": [
"class-span4"
],
"level": 1
},
{
"name": "ID selector, matching element with specified id",
"selector": "#id #id-div1",
"expect": [
"id-div1"
],
"level": 1
},
{
"name": "ID selector, chained, matching element with specified id",
"selector": "#id-div1, #id-div1",
"expect": [
"id-div1"
],
"level": 1
},
{
"name": "ID selector, chained, matching element with specified id",
"selector": "#id-div1, #id-div2",
"expect": [
"id-div1",
"id-div2"
],
"level": 1
},
{
"name": "ID Selector, chained, with type selector",
"selector": "div#id-div1, div#id-div2",
"expect": [
"id-div1",
"id-div2"
],
"level": 1
},
{
"name": "ID selector, not matching non-existent descendant",
"selector": "#id #none",
"expect": [],
"level": 1
},
{
"name": "ID selector, not matching non-existent ancestor",
"selector": "#none #id-div1",
"expect": [],
"level": 1
},
{
"name": "ID selector, matching multiple elements with duplicate id",
"selector": "#id-li-duplicate",
"expect": [
"id-li-duplicate",
"id-li-duplicate",
"id-li-duplicate",
"id-li-duplicate"
],
"level": 1
},
{
"name": "ID selector, matching id value using non-ASCII characters",
"selector": "#台北Táiběi",
"expect": [
"台北Táiběi"
],
"level": 1
},
{
"name": "ID selector, matching id value using non-ASCII characters",
"selector": "#台北",
"expect": [
"台北"
],
"level": 1
},
{
"name": "ID selector, matching id values using non-ASCII characters",
"selector": "#台北Táiběi, #台北",
"expect": [
"台北Táiběi",
"台北"
],
"level": 1
},
{
"name": "ID selector, matching element with id with escaped character",
"selector": "#\\#foo\\:bar",
"expect": [
"#foo:bar"
],
"level": 1
},
{
"name": "ID selector, matching element with id with escaped character",
"selector": "#test\\.foo\\[5\\]bar",
"expect": [
"test.foo[5]bar"
],
"level": 1
},
{
"name": "Namespace selector, matching element with any namespace",
"selector": "#any-namespace *|div",
"expect": [
"any-namespace-div1",
"any-namespace-div2",
"any-namespace-div3",
"any-namespace-div4"
],
"level": 3,
"xfail": true
},
{
"name": "Namespace selector, matching div elements in no namespace only",
"selector": "#no-namespace |div",
"expect": [
"no-namespace-div3"
],
"level": 3,
"xfail": true
},
{
"name": "Namespace selector, matching any elements in no namespace only",
"selector": "#no-namespace |*",
"expect": [
"no-namespace-div3"
],
"level": 3,
"xfail": true
},
{
"name": "Descendant combinator, matching element that is a descendant of an element with id",
"selector": "#descendant div",
"expect": [
"descendant-div1",
"descendant-div2",
"descendant-div3",
"descendant-div4"
],
"level": 1
},
{
"name": "Descendant combinator, matching element with id that is a descendant of an element",
"selector": "body #descendant-div1",
"expect": [
"descendant-div1"
],
"exclude": [
"detached",
"fragment"
],
"level": 1
},
{
"name": "Descendant combinator, matching element with id that is a descendant of an element",
"selector": "div #descendant-div1",
"expect": [
"descendant-div1"
],
"level": 1
},
{
"name": "Descendant combinator, matching element with id that is a descendant of an element with id",
"selector": "#descendant #descendant-div2",
"expect": [
"descendant-div2"
],
"level": 1
},
{
"name": "Descendant combinator, matching element with class that is a descendant of an element with id",
"selector": "#descendant .descendant-div2",
"expect": [
"descendant-div2"
],
"level": 1
},
{
"name": "Descendant combinator, matching element with class that is a descendant of an element with class",
"selector": ".descendant-div1 .descendant-div3",
"expect": [
"descendant-div3"
],
"level": 1
},
{
"name": "Descendant combinator, not matching element with id that is not a descendant of an element with id",
"selector": "#descendant-div1 #descendant-div4",
"expect": [],
"level": 1
},
{
"name": "Descendant combinator, whitespace characters",
"selector": "#descendant\t\r\n#descendant-div2",
"expect": [
"descendant-div2"
],
"level": 1
},
{
"name": "Child combinator, matching element that is a child of an element with id",
"selector": "#child>div",
"expect": [
"child-div1",
"child-div4"
],
"level": 2
},
{
"name": "Child combinator, matching element with id that is a child of an element",
"selector": "div>#child-div1",
"expect": [
"child-div1"
],
"level": 2
},
{
"name": "Child combinator, matching element with id that is a child of an element with id",
"selector": "#child>#child-div1",
"expect": [
"child-div1"
],
"level": 2
},
{
"name": "Child combinator, matching element with id that is a child of an element with class",
"selector": "#child-div1>.child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Child combinator, matching element with class that is a child of an element with class",
"selector": ".child-div1>.child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Child combinator, not matching element with id that is not a child of an element with id",
"selector": "#child>#child-div3",
"expect": [],
"level": 2
},
{
"name": "Child combinator, not matching element with id that is not a child of an element with class",
"selector": "#child-div1>.child-div3",
"expect": [],
"level": 2
},
{
"name": "Child combinator, not matching element with class that is not a child of an element with class",
"selector": ".child-div1>.child-div3",
"expect": [],
"level": 2
},
{
"name": "Child combinator, surrounded by whitespace",
"selector": "#child-div1\t\r\n>\t\r\n#child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Child combinator, whitespace after",
"selector": "#child-div1>\t\r\n#child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Child combinator, whitespace before",
"selector": "#child-div1\t\r\n>#child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Child combinator, no whitespace",
"selector": "#child-div1>#child-div2",
"expect": [
"child-div2"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id",
"selector": "#adjacent-div2+div",
"expect": [
"adjacent-div4"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element",
"selector": "div+#adjacent-div4",
"expect": [
"adjacent-div4"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id",
"selector": "#adjacent-div2+#adjacent-div4",
"expect": [
"adjacent-div4"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id",
"selector": "#adjacent-div2+.adjacent-div4",
"expect": [
"adjacent-div4"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class",
"selector": ".adjacent-div2+.adjacent-div4",
"expect": [
"adjacent-div4"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element",
"selector": "#adjacent div+p",
"expect": [
"adjacent-p2"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id",
"selector": "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1",
"expect": [],
"level": 2
},
{
"name": "Adjacent sibling combinator, surrounded by whitespace",
"selector": "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3",
"expect": [
"adjacent-p3"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, whitespace after",
"selector": "#adjacent-p2+\t\r\n#adjacent-p3",
"expect": [
"adjacent-p3"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, whitespace before",
"selector": "#adjacent-p2\t\r\n+#adjacent-p3",
"expect": [
"adjacent-p3"
],
"level": 2
},
{
"name": "Adjacent sibling combinator, no whitespace",
"selector": "#adjacent-p2+#adjacent-p3",
"expect": [
"adjacent-p3"
],
"level": 2
},
{
"name": "General sibling combinator, matching element that is a sibling of an element with id",
"selector": "#sibling-div2~div",
"expect": [
"sibling-div4",
"sibling-div6"
],
"level": 3
},
{
"name": "General sibling combinator, matching element with id that is a sibling of an element",
"selector": "div~#sibling-div4",
"expect": [
"sibling-div4"
],
"level": 3
},
{
"name": "General sibling combinator, matching element with id that is a sibling of an element with id",
"selector": "#sibling-div2~#sibling-div4",
"expect": [
"sibling-div4"
],
"level": 3
},
{
"name": "General sibling combinator, matching element with class that is a sibling of an element with id",
"selector": "#sibling-div2~.sibling-div",
"expect": [
"sibling-div4",
"sibling-div6"
],
"level": 3
},
{
"name": "General sibling combinator, matching p element that is a sibling of a div element",
"selector": "#sibling div~p",
"expect": [
"sibling-p2",
"sibling-p3"
],
"level": 3
},
{
"name": "General sibling combinator, not matching element with id that is not a sibling after a p element",
"selector": "#sibling>p~div",
"expect": [],
"level": 3
},
{
"name": "General sibling combinator, not matching element with id that is not a sibling after an element with id",
"selector": "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1",
"expect": [],
"level": 3
},
{
"name": "General sibling combinator, surrounded by whitespace",
"selector": "#sibling-p2\t\r\n~\t\r\n#sibling-p3",
"expect": [
"sibling-p3"
],
"level": 3
},
{
"name": "General sibling combinator, whitespace after",
"selector": "#sibling-p2~\t\r\n#sibling-p3",
"expect": [
"sibling-p3"
],
"level": 3
},
{
"name": "General sibling combinator, whitespace before",
"selector": "#sibling-p2\t\r\n~#sibling-p3",
"expect": [
"sibling-p3"
],
"level": 3
},
{
"name": "General sibling combinator, no whitespace",
"selector": "#sibling-p2~#sibling-p3",
"expect": [
"sibling-p3"
],
"level": 3
},
{
"name": "Syntax, group of selectors separator, surrounded by whitespace",
"selector": "#group em\t\r \n,\t\r \n#group strong",
"expect": [
"group-em1",
"group-strong1"
],
"level": 1
},
{
"name": "Syntax, group of selectors separator, whitespace after",
"selector": "#group em,\t\r\n#group strong",
"expect": [
"group-em1",
"group-strong1"
],
"level": 1
},
{
"name": "Syntax, group of selectors separator, whitespace before",
"selector": "#group em\t\r\n,#group strong",
"expect": [
"group-em1",
"group-strong1"
],
"level": 1
},
{
"name": "Syntax, group of selectors separator, no whitespace",
"selector": "#group em,#group strong",
"expect": [
"group-em1",
"group-strong1"
],
"level": 1
}
] cascadia-1.3.3/w3_test.go 0000664 0000000 0000000 00000004360 14731063146 0015175 0 ustar 00root root 0000000 0000000 package cascadia
import (
"encoding/json"
"io/ioutil"
"log"
"os"
"reflect"
"testing"
"golang.org/x/net/html"
)
func TestInvalidSelectors(t *testing.T) {
c, err := ioutil.ReadFile("test_resources/invalid_selectors.json")
if err != nil {
t.Fatal(err)
}
var tests []invalidSelector
if err = json.Unmarshal(c, &tests); err != nil {
t.Fatal(err)
}
for _, test := range tests {
_, err := ParseGroupWithPseudoElements(test.Selector)
if err == nil {
t.Fatalf("%s -> expected error on invalid selector : %s", test.Name, test.Selector)
}
}
}
func parseReference(filename string) *html.Node {
f, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
node, err := html.Parse(f)
if err != nil {
log.Fatal(err)
}
return node
}
func getId(n *html.Node) string {
for _, attr := range n.Attr {
if attr.Key == "id" {
return attr.Val
}
}
return ""
}
func isEqual(m map[string]int, l []string) bool {
expected := map[string]int{}
for _, s := range l {
expected[s]++
}
return reflect.DeepEqual(m, expected)
}
func loadValidSelectors(t *testing.T) []validSelector {
c, err := ioutil.ReadFile("test_resources/valid_selectors.json")
if err != nil {
t.Fatal(err)
}
var tests []validSelector
if err = json.Unmarshal(c, &tests); err != nil {
t.Fatal(err)
}
return tests
}
func TestValidSelectors(t *testing.T) {
tests := loadValidSelectors(t)
doc := parseReference("test_resources/content.xhtml")
for i, test := range tests {
if test.Xfail {
t.Logf("skiped test %s", test.Name)
continue
}
sels, err := ParseGroupWithPseudoElements(test.Selector)
if err != nil {
t.Fatalf("%s -> unable to parse valid selector : %s : %s", test.Name, test.Selector, err)
}
matchingNodes := map[*html.Node]bool{}
for _, sel := range sels {
if sel.PseudoElement() != "" {
continue // pseudo element doesn't count as a match in this test since they are not part of the document
}
for _, node := range Selector(sel.Match).MatchAll(doc) {
matchingNodes[node] = true
}
}
matchingIds := map[string]int{}
for node := range matchingNodes {
matchingIds[getId(node)]++
}
if !isEqual(matchingIds, test.Expect) {
t.Fatalf("test %d %s : expected %v got %v", i, test.Name, test.Expect, matchingIds)
}
}
}