File: superselector_test.rb

package info (click to toggle)
ruby-sass 3.7.4-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,396 kB
  • sloc: ruby: 32,443; sh: 26; makefile: 25
file content (209 lines) | stat: -rwxr-xr-x 7,982 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
require File.dirname(__FILE__) + '/../test_helper'

class SuperselectorTest < Minitest::Test
  def test_superselector_reflexivity
    assert_superselector 'h1', 'h1'
    assert_superselector '.foo', '.foo'
    assert_superselector '#foo > .bar, baz', '#foo > .bar, baz'
  end

  def test_smaller_compound_superselector
    assert_strict_superselector '.foo', '.foo.bar'
    assert_strict_superselector '.bar', '.foo.bar'
    assert_strict_superselector 'a', 'a#b'
    assert_strict_superselector '#b', 'a#b'
  end

  def test_smaller_complex_superselector
    assert_strict_superselector '.bar', '.foo .bar'
    assert_strict_superselector '.bar', '.foo > .bar'
    assert_strict_superselector '.bar', '.foo + .bar'
    assert_strict_superselector '.bar', '.foo ~ .bar'
  end

  def test_selector_list_subset_superselector
    assert_strict_superselector '.foo, .bar', '.foo'
    assert_strict_superselector '.foo, .bar, .baz', '.foo, .baz'
    assert_strict_superselector '.foo, .baz, .qux', '.foo.bar, .baz.bang'
  end

  def test_leading_combinator_superselector
    refute_superselector '+ .foo', '.foo'
    refute_superselector '+ .foo', '.bar + .foo'
  end

  def test_trailing_combinator_superselector
    refute_superselector '.foo +', '.foo'
    refute_superselector '.foo +', '.foo + .bar'
  end

  def test_matching_combinator_superselector
    assert_strict_superselector '.foo + .bar', '.foo + .bar.baz'
    assert_strict_superselector '.foo + .bar', '.foo.baz + .bar'
    assert_strict_superselector '.foo > .bar', '.foo > .bar.baz'
    assert_strict_superselector '.foo > .bar', '.foo.baz > .bar'
    assert_strict_superselector '.foo ~ .bar', '.foo ~ .bar.baz'
    assert_strict_superselector '.foo ~ .bar', '.foo.baz ~ .bar'
  end

  def test_following_sibling_is_superselector_of_next_sibling
    assert_strict_superselector '.foo ~ .bar', '.foo + .bar.baz'
    assert_strict_superselector '.foo ~ .bar', '.foo.baz + .bar'
  end

  def test_descendant_is_superselector_of_child
    assert_strict_superselector '.foo .bar', '.foo > .bar.baz'
    assert_strict_superselector '.foo .bar', '.foo.baz > .bar'
    assert_strict_superselector '.foo .baz', '.foo > .bar > .baz'
  end

  def test_child_isnt_superselector_of_longer_child
    refute_superselector '.foo > .baz', '.foo > .bar > .baz'
    refute_superselector '.foo > .baz', '.foo > .bar .baz'
  end

  def test_following_sibling_isnt_superselector_of_longer_following_sibling
    refute_superselector '.foo + .baz', '.foo + .bar + .baz'
    refute_superselector '.foo + .baz', '.foo + .bar .baz'
  end

  def test_sibling_isnt_superselector_of_longer_sibling
    # This actually is a superselector, but it's a very narrow edge case and
    # detecting it is very difficult and may be exponential in the worst case.
    refute_superselector '.foo ~ .baz', '.foo ~ .bar ~ .baz'

    refute_superselector '.foo ~ .baz', '.foo ~ .bar .baz'
  end

  def test_matches_is_superselector_of_constituent_selectors
    %w[matches -moz-any].each do |name|
      assert_strict_superselector ":#{name}(.foo, .bar)", '.foo.baz'
      assert_strict_superselector ":#{name}(.foo, .bar)", '.bar.baz'
      assert_strict_superselector ":#{name}(.foo .bar, .baz)", '.x .foo .bar'
    end
  end

  def test_matches_is_superselector_of_subset_matches
    assert_strict_superselector ':matches(.foo, .bar, .baz)', '#x:matches(.foo.bip, .baz.bang)'
    assert_strict_superselector ':-moz-any(.foo, .bar, .baz)', '#x:-moz-any(.foo.bip, .baz.bang)'
  end

  def test_matches_is_not_superselector_of_any
    refute_superselector ':matches(.foo, .bar)', ':-moz-any(.foo, .bar)'
    refute_superselector ':-moz-any(.foo, .bar)', ':matches(.foo, .bar)'
  end

  def test_matches_can_be_subselector
    %w[matches -moz-any].each do |name|
      assert_superselector '.foo', ":#{name}(.foo.bar)"
      assert_superselector '.foo.bar', ":#{name}(.foo.bar.baz)"
      assert_superselector '.foo', ":#{name}(.foo.bar, .foo.baz)"
    end
  end

  def test_any_is_not_superselector_of_different_prefix
    refute_superselector ':-moz-any(.foo, .bar)', ':-s-any(.foo, .bar)'
  end

  def test_not_is_superselector_of_less_complex_not
    assert_strict_superselector ':not(.foo.bar)', ':not(.foo)'
    assert_strict_superselector ':not(.foo .bar)', ':not(.bar)'
  end

  def test_not_is_superselector_of_superset
    assert_strict_superselector ':not(.foo.bip, .baz.bang)', ':not(.foo, .bar, .baz)'
    assert_strict_superselector ':not(.foo.bip, .baz.bang)', ':not(.foo):not(.bar):not(.baz)'
  end

  def test_not_is_superselector_of_unique_selectors
    assert_strict_superselector ':not(h1.foo)', 'a'
    assert_strict_superselector ':not(.baz #foo)', '#bar'
  end

  def test_not_is_not_superselector_of_non_unique_selectors
    refute_superselector ':not(.foo)', '.bar'
    refute_superselector ':not(:hover)', ':visited'
  end

  def test_current_is_superselector_with_identical_innards
    assert_superselector ':current(.foo)', ':current(.foo)'
  end

  def test_current_is_superselector_with_subselector_innards
    refute_superselector ':current(.foo)', ':current(.foo.bar)'
    refute_superselector ':current(.foo.bar)', ':current(.foo)'
  end

  def test_nth_match_is_superselector_of_subset_nth_match
    assert_strict_superselector(
      ':nth-child(2n of .foo, .bar, .baz)', '#x:nth-child(2n of .foo.bip, .baz.bang)')
    assert_strict_superselector(
      ':nth-last-child(2n of .foo, .bar, .baz)', '#x:nth-last-child(2n of .foo.bip, .baz.bang)')
  end

  def test_nth_match_is_not_superselector_of_nth_match_with_different_arg
    refute_superselector(
      ':nth-child(2n of .foo, .bar, .baz)', '#x:nth-child(2n + 1 of .foo.bip, .baz.bang)')
    refute_superselector(
      ':nth-last-child(2n of .foo, .bar, .baz)', '#x:nth-last-child(2n + 1 of .foo.bip, .baz.bang)')
  end

  def test_nth_match_is_not_superselector_of_nth_last_match
    refute_superselector ':nth-child(2n of .foo, .bar)', ':nth-last-child(2n of .foo, .bar)'
    refute_superselector ':nth-last-child(2n of .foo, .bar)', ':nth-child(2n of .foo, .bar)'
  end

  def test_nth_match_can_be_subselector
    %w[nth-child nth-last-child].each do |name|
      assert_superselector '.foo', ":#{name}(2n of .foo.bar)"
      assert_superselector '.foo.bar', ":#{name}(2n of .foo.bar.baz)"
      assert_superselector '.foo', ":#{name}(2n of .foo.bar, .foo.baz)"
    end
  end

  def has_is_superselector_of_subset_host
    assert_strict_superselector ':has(.foo, .bar, .baz)', ':has(.foo.bip, .baz.bang)'
  end

  def has_isnt_superselector_of_contained_selector
    assert_strict_superselector ':has(.foo, .bar, .baz)', '.foo'
  end

  def host_is_superselector_of_subset_host
    assert_strict_superselector ':host(.foo, .bar, .baz)', ':host(.foo.bip, .baz.bang)'
  end

  def host_isnt_superselector_of_contained_selector
    assert_strict_superselector ':host(.foo, .bar, .baz)', '.foo'
  end

  def host_context_is_superselector_of_subset_host
    assert_strict_superselector(
      ':host-context(.foo, .bar, .baz)', ':host-context(.foo.bip, .baz.bang)')
  end

  def host_context_isnt_superselector_of_contained_selector
    assert_strict_superselector ':host-context(.foo, .bar, .baz)', '.foo'
  end

  private

  def assert_superselector(superselector, subselector)
    assert(parse_selector(superselector).superselector?(parse_selector(subselector)),
      "Expected #{superselector} to be a superselector of #{subselector}.")
  end

  def refute_superselector(superselector, subselector)
    assert(!parse_selector(superselector).superselector?(parse_selector(subselector)),
      "Expected #{superselector} not to be a superselector of #{subselector}.")
  end

  def assert_strict_superselector(superselector, subselector)
    assert_superselector(superselector, subselector)
    refute_superselector(subselector, superselector)
  end

  def parse_selector(selector)
    Sass::SCSS::CssParser.new(selector, filename_for_test, nil).parse_selector
  end
end