Package cssutils :: Package tests :: Module test_selector |
[hide private]
[frames] | no frames]

# Source Code for Module cssutils.tests.test_selector

      1  """Testcases for cssutils.css.selector.Selector.
      2
      3  what should happen here?
      4      - star 7 hack::
      5          x*
      6          does not validate but works in IE>5 and FF, does it???
      7
      8  """
      9  __author__ = '$LastChangedBy: cthedot $'
     10  __date__ = '$LastChangedDate: 2008-02-22 19:03:20 +0100 (Fr, 22 Feb 2008) $'
     11  __version__ = '$LastChangedRevision: 1070 $'
     12
     13  import xml.dom
     14  import basetest
     15  import cssutils
     16
     17 -class SelectorTestCase(basetest.BaseTestCase):
     18
     19 -    def setUp(self):
     20          self.r = cssutils.css.Selector('*')
     21
     22 -    def test_init(self):
     23          "Selector.__init__()"
     24          s = cssutils.css.Selector('*')
     25          self.assertEqual((None, '*'), s.element)
     26          self.assertEqual({}, s._namespaces.namespaces)
     27          self.assertEqual(None, s.parentList)
     28          self.assertEqual('*', s.selectorText)
     29          self.assertEqual((0,0,0,0), s.specificity)
     30          self.assertEqual(True, s.wellformed)
     31
     32          s = cssutils.css.Selector(('p|b', {'p': 'URI'}) )
     33          self.assertEqual(('URI', 'b'), s.element)
     34          self.assertEqual({'p': 'URI'}, s._namespaces.namespaces)
     35          self.assertEqual(None, s.parentList)
     36          self.assertEqual('p|b', s.selectorText)
     37          self.assertEqual((0,0,0,1), s.specificity)
     38          self.assertEqual(True, s.wellformed)
     39
     40          self.assertRaisesEx(xml.dom.NamespaceErr, cssutils.css.Selector, 'p|b')
     41
     42 -    def test_element(self):
     43          "Selector.element (TODO: RESOLVE)"
     44          tests = {
     45              '*': (None, '*'),
     46              'x': (None, 'x'),
     47              '\\x': (None, '\\x'),
     48              '|x': (u'', 'x'),
     49              '*|x': (cssutils._ANYNS, 'x'),
     50              'ex|x': (u'example', 'x'),
     51              'a x': (None, 'x'),
     52              'a+x': (None, 'x'),
     53              'a>x': (None, 'x'),
     54              'a~x': (None, 'x'),
     55              'a+b~c x': (None, 'x'),
     56              'x[href]': (None, 'x'),
     57              'x[href="123"]': (None, 'x'),
     58              'x:hover': (None, 'x'),
     59              'x:first-letter': (None, 'x'), # TODO: Really?
     60              'x::first-line': (None, 'x'), # TODO: Really?
     61              'x:not(href)': (None, 'x'), # TODO: Really?
     62
     63              '#id': None,
     64              '.c': None,
     65              'x#id': (None, 'x'),
     66              'x.c': (None, 'x')
     67          }
     68          for test, ele in tests.items():
     69              s = cssutils.css.Selector((test,{'ex': 'example'}))
     70              self.assertEqual(ele, s.element)
     71
     72 -    def test_namespaces(self):
     73          "Selector.namespaces"
     74          namespaces = [
     75              {'p': 'other'}, # no default
     76              {'': 'default', 'p': 'other'}, # with default
     77              {'': 'default', 'p': 'default' } # same default
     78              ]
     79          tests = {
     80              # selector: with default, no default, same default
     81              '*': ('*', '*', '*'),
     82              'x': ('x', 'x', 'x'),
     83              '|*': ('|*', '|*', '|*'),
     84              '|x': ('|x', '|x', '|x'),
     85              '*|*': ('*|*', '*|*', '*|*'),
     86              '*|x': ('*|x', '*|x', '*|x'),
     87              'p|*': ('p|*', 'p|*', '*'),
     88              'p|x': ('p|x', 'p|x', 'x'),
     89              'x[a][|a][*|a][p|a]': ('x[a][a][*|a][p|a]',
     90                                     'x[a][a][*|a][p|a]',
     91                                     'x[a][a][*|a][a]')
     92          }
     93          for sel, exp in tests.items():
     94              for i, result in enumerate(exp):
     95                  s = cssutils.css.Selector((sel, namespaces[i]))
     96                  self.assertEqual(result, s.selectorText)
     97
     98          # add to CSSStyleSheet
     99          sheet = cssutils.css.CSSStyleSheet()
    100          sheet.cssText = '@namespace p "u"; a { color: green }'
    101
    102          r = sheet.cssRules[1]
    103
    104          self.assertEqual(r.selectorText, u'a')
    105
    106          # add default namespace
    107          sheet.namespaces[''] = 'a';
    108          self.assertEqual(r.selectorText, u'|a')
    109
    110          del sheet.namespaces[''];
    111          self.assertEqual(r.selectorText, u'a')
    112
    113  #        r.selectorList.append('a')
    114  #        self.assertEqual(r.selectorText, u'|a, a')
    115  #        r.selectorList.append('*|a')
    116  #        self.assertEqual(r.selectorText, u'|a, a, *|a')
    117
    118 -    def test_default_namespace(self):
    119          "Selector.namespaces default"
    120          css = '''@namespace "default";
    121                  a[att] { color:green; }
    122          '''
    123          sheet = cssutils.css.CSSStyleSheet()
    124          sheet.cssText = css
    125          self.assertEqual(sheet.cssText,
    126                           u'@namespace "default";\na[att] {\n    color: green\n    }')
    127          # use a prefix for default namespace, does not goes for atts!
    128          sheet.namespaces['p'] = 'default'
    129          self.assertEqual(sheet.cssText,
    130                           u'@namespace p "default";\np|a[att] {\n    color: green\n    }')
    131
    132 -    def test_parentList(self):
    133          "Selector.parentList"
    134          sl = cssutils.css.SelectorList('a, b')
    135          for sel in sl:
    136              self.assertEqual(sl, sel.parentList)
    137
    138          newsel = cssutils.css.Selector('x')
    139          sl.append(newsel)
    140          self.assertEqual(sl, newsel.parentList)
    141
    142          newsel = cssutils.css.Selector('y')
    143          sl.appendSelector(newsel)
    144          self.assertEqual(sl, newsel.parentList)
    145
    146 -    def test_selectorText(self):
    147          "Selector.selectorText"
    148          tests = {
    149              # combinators
    150              u'a+b>c~e f': u'a + b > c ~ e f',
    151              u'a  +  b  >  c  ~  e   f': u'a + b > c ~ e f',
    152              u'a+b': u'a + b',
    153              u'a  +  b': 'a + b',
    154              u'a\n  +\t  b': 'a + b',
    155              u'a~b': u'a ~ b',
    156              u'a b': None,
    157              u'a   b': 'a b',
    158              u'a\nb': 'a b',
    159              u'a\tb': 'a b',
    160              u'a   #b': 'a #b',
    161              u'a   .b': 'a .b',
    162              u'a * b': None,
    163              # >
    164              u'a>b': u'a > b',
    165              u'a> b': 'a > b',
    166              u'a >b': 'a > b',
    167              u'a > b': 'a > b',
    168              # +
    169              u'a+b': u'a + b',
    170              u'a+ b': 'a + b',
    171              u'a +b': 'a + b',
    172              u'a + b': 'a + b',
    173              # ~
    174              u'a~b': u'a ~ b',
    175              u'a~ b': 'a ~ b',
    176              u'a ~b': 'a ~ b',
    177              u'a ~ b': 'a ~ b',
    178
    179              # type selector
    180              u'a': None,
    181              u'h1-a_x__--': None,
    182              u'a-a': None,
    183              u'a_a': None,
    184              u'-a': None,
    185              u'_': None,
    186              u'-_': None,
    187              ur'-\72': u'-r',
    188              #ur'\25': u'%', # TODO: should be escaped!
    189              u'.a a': None,
    190              u'a1': None,
    191              u'a1-1': None,
    192              u'.a1-1': None,
    193
    194              # universal
    195              u'*': None,
    196              u'*/*x*/': None,
    197              u'* /*x*/': None,
    198              u'*:hover': None,
    199              u'* :hover': None,
    200              u'*:lang(fr)': None,
    201              u'* :lang(fr)': None,
    202              u'*::first-line': None,
    203              u'* ::first-line': None,
    204              u'*[lang=fr]': None,
    205              u'[lang=fr]': None,
    206
    207              # HASH
    208              u'''#a''': None,
    209              u'''#a1''': None,
    210              u'''#1a''': None, # valid to grammar but not for HTML
    211              u'''#1''': None, # valid to grammar but not for HTML
    212              u'''a#b''': None,
    213              u'''a #b''': None,
    214              u'''a#b.c''': None,
    215              u'''a.c#b''': None,
    216              u'''a #b.c''': None,
    217              u'''a .c#b''': None,
    218
    219              # class
    220              u'ab': 'ab',
    221              u'a.b': None,
    222              u'a.b.c': None,
    223              u'.a1._1': None,
    224
    225              # attrib
    226              u'''[x]''': None,
    227              u'''*[x]''': None,
    228              u'''a[x]''': None,
    229              u'''a[ x]''': 'a[x]',
    230              u'''a[x ]''': 'a[x]',
    231              u'''a [x]''': 'a [x]',
    232              u'''* [x]''': None, # is really * *[x]
    233
    234              u'''a[x="1"]''': None,
    235              u'''a[x ="1"]''': 'a[x="1"]',
    236              u'''a[x= "1"]''': 'a[x="1"]',
    237              u'''a[x = "1"]''': 'a[x="1"]',
    238              u'''a[ x = "1"]''': 'a[x="1"]',
    239              u'''a[x = "1" ]''': 'a[x="1"]',
    240              u'''a[ x = "1" ]''': 'a[x="1"]',
    241              u'''a [ x = "1" ]''': 'a [x="1"]',
    242
    243              u'''a[x~=a1]''': None,
    244              u'''a[x ~=a1]''': 'a[x~=a1]',
    245              u'''a[x~= a1]''': 'a[x~=a1]',
    246              u'''a[x ~= a1]''': 'a[x~=a1]',
    247              u'''a[ x ~= a1]''': 'a[x~=a1]',
    248              u'''a[x ~= a1 ]''': 'a[x~=a1]',
    249              u'''a[ x ~= a1 ]''': 'a[x~=a1]',
    250              u'''a [ x ~= a1 ]''': 'a [x~=a1]', # same as next!
    251              u'''a *[ x ~= a1 ]''': 'a *[x~=a1]',
    252
    253              u'''a[x|=en]''': None,
    254              u'''a[x|= en]''': 'a[x|=en]',
    255              u'''a[x |=en]''': 'a[x|=en]',
    256              u'''a[x |= en]''': 'a[x|=en]',
    257              u'''a[ x |= en]''': 'a[x|=en]',
    258              u'''a[x |= en ]''': 'a[x|=en]',
    259              u'''a[ x |= en]''': 'a[x|=en]',
    260              u'''a [ x |= en]''': 'a [x|=en]',
    261              # CSS3
    262              u'''a[x^=en]''': None,
    263              u'''a[x$=en]''': None,
    264              u'''a[x*=en]''': None,
    265
    266              u'''a[/*1*/x/*2*/]''': None,
    267              u'''a[/*1*/x/*2*/=/*3*/a/*4*/]''': None,
    268              u'''a[/*1*/x/*2*/~=/*3*/a/*4*/]''': None,
    269              u'''a[/*1*/x/*2*/|=/*3*/a/*4*/]''': None,
    270
    271              # pseudo-elements
    272              u'a x:first-line': None,
    273              u'a x:first-letter': None,
    274              u'a x:before': None,
    275              u'a x:after': None,
    276              u'a x::selection': None,
    277              u'a:hover+b:hover>c:hover~e:hover f:hover':
    278                  u'a:hover + b:hover > c:hover ~ e:hover f:hover',
    279              u'a:hover  +  b:hover  >  c:hover  ~  e:hover   f:hover':
    280                  u'a:hover + b:hover > c:hover ~ e:hover f:hover',
    281              u'a::selection+b::selection>c::selection~e::selection f::selection':
    282                  u'a::selection + b::selection > c::selection ~ e::selection f::selection',
    283              u'a::selection  +  b::selection  >  c::selection  ~  e::selection   f::selection':
    284                  u'a::selection + b::selection > c::selection ~ e::selection f::selection',
    285
    286              u'x:lang(de) y': None,
    287              u'x:nth-child(odd) y': None,
    288              # functional pseudo
    289              u'x:func(a + b-2px22.3"s"i)': None,
    290              u'x:func(1 + 1)': None,
    291              u'x:func(1+1)': u'x:func(1 + 1)',
    292              u'x:func(1   +   1)': u'x:func(1 + 1)',
    293              u'x:func(1-1)': u'x:func(1-1)',
    294              u'x:func(1  -  1)': u'x:func(1 -1)',
    295              u'x:func(a-1)': u'x:func(a-1)',
    296              u'x:func(a -1px)': u'x:func(a -1px)',
    297              u'x:func(1px)': None,
    298              u'x:func(23.4)': None,
    299              u'x:func("s")': None,
    300              u'x:func(i)': None,
    301
    302              # negation
    303              u':not(y)': None,
    304              u':not(   y  \t\n)': u':not(y)',
    305              u'*:not(y)': None,
    306              u'x:not(y)': None,
    307              u'.x:not(y)': None,
    308              u':not(*)': None,
    309              u':not(#a)': None,
    310              u':not(.a)': None,
    311              u':not([a])': None,
    312              u':not(:first-letter)': None,
    313              u':not(::first-letter)': None,
    314
    315              # escapes
    316              ur'\74\72 td': 'trtd',
    317              ur'\74\72  td': 'tr td',
    318              ur'\74\000072 td': 'trtd',
    319              ur'\74\000072  td': 'tr td',
    320
    321              # comments
    322              u'a/**/ b': None,
    323              u'a /**/b': None,
    324              u'a /**/ b': None,
    325              u'a  /**/ b': u'a /**/ b',
    326              u'a /**/  b': u'a /**/ b',
    327
    328              # namespaces
    329              u'|e': None,
    330              u'*|e': None,
    331              u'*|*': None,
    332              (u'p|*', (('p', 'uri'),)): u'p|*',
    333              (u'p|e', (('p', 'uri'),)): u'p|e',
    334              (u'-a_x12|e', (('-a_x12', 'uri'),)): u'-a_x12|e',
    335              (u'*|b[p|a]', (('p', 'uri'),)): '*|b[p|a]',
    336
    337              # case
    338              u'elemenT.clasS#iD[atT="valuE"]:noT(x)::firsT-linE':
    339                  u'elemenT.clasS#iD[atT="valuE"]:not(x)::first-line'
    340              }
    341          # do not parse as not complete
    342          self.do_equal_r(tests, att='selectorText')
    343
    344          tests = {
    345              u'x|a': xml.dom.NamespaceErr,
    346              (u'p|*', (('x', 'uri'),)): xml.dom.NamespaceErr,
    347
    348              u'': xml.dom.SyntaxErr,
    349              u'1': xml.dom.SyntaxErr,
    350              u'-1': xml.dom.SyntaxErr,
    351              u'a*b': xml.dom.SyntaxErr,
    352              u'a *b': xml.dom.SyntaxErr,
    353              u'a* b': xml.dom.SyntaxErr,
    354              u'a/**/b': xml.dom.SyntaxErr,
    355
    356              u'#': xml.dom.SyntaxErr,
    357              u'|': xml.dom.SyntaxErr,
    358
    359              u':': xml.dom.SyntaxErr,
    360              u'::': xml.dom.SyntaxErr,
    361              u': a': xml.dom.SyntaxErr,
    362              u':: a': xml.dom.SyntaxErr,
    363              u':a()': xml.dom.SyntaxErr, # no value
    364              u'::a()': xml.dom.SyntaxErr, # no value
    365              u':::a': xml.dom.SyntaxErr,
    366              u':1': xml.dom.SyntaxErr,
    367
    368              u'#.x': xml.dom.SyntaxErr,
    369              u'.': xml.dom.SyntaxErr,
    370              u'.1': xml.dom.SyntaxErr,
    371              u'.a.1': xml.dom.SyntaxErr,
    372
    373              u'[a': xml.dom.SyntaxErr,
    374              u'a]': xml.dom.SyntaxErr,
    375              u'[a b]': xml.dom.SyntaxErr,
    376              u'[=b]': xml.dom.SyntaxErr,
    377              u'[a=]': xml.dom.SyntaxErr,
    378              u'[a|=]': xml.dom.SyntaxErr,
    379              u'[a~=]': xml.dom.SyntaxErr,
    380              u'[a=1]': xml.dom.SyntaxErr,
    381
    382              u'a +': xml.dom.SyntaxErr,
    383              u'a >': xml.dom.SyntaxErr,
    384              u'a ++ b': xml.dom.SyntaxErr,
    385              u'a + > b': xml.dom.SyntaxErr,
    386
    387              # functional pseudo
    388              u'*:lang(': xml.dom.SyntaxErr,
    389              u'*:lang()': xml.dom.SyntaxErr, # no arg
    390
    391              # negation
    392              u'not(x)': xml.dom.SyntaxErr, # no valid function
    393              u':not()': xml.dom.SyntaxErr, # no arg
    394              u':not(x': xml.dom.SyntaxErr, # no )
    395              u':not(-': xml.dom.SyntaxErr, # not allowed
    396              u':not(+': xml.dom.SyntaxErr, # not allowed
    397
    398              # only one selector!
    399              u',': xml.dom.InvalidModificationErr,
    400              u',a': xml.dom.InvalidModificationErr,
    401              u'a,': xml.dom.InvalidModificationErr,
    402              }
    403          # only set as not complete
    404          self.do_raise_r(tests, att='_setSelectorText')
    405
    406 -    def test_specificity(self):
    407          "Selector.specificity"
    408          selector = cssutils.css.Selector()
    409
    410          # readonly
    411          def _set(): selector.specificity = 1
    412          self.assertRaisesMsg(AttributeError, "can't set attribute", _set)
    413
    414          tests = {
    415              u'*': (0,0,0,0),
    416              u'li': (0,0,0,1),
    417              u'li:first-line': (0,0,0,2),
    418              u'ul li': (0,0,0,2),
    419              u'ul ol+li': (0,0,0,3),
    420              u'h1 + *[rel=up]': (0,0,1,1),
    421              u'ul ol li.red': (0,0,1,3),
    422              u'li.red.level': (0,0,2,1),
    423              u'#x34y': (0,1,0,0),
    424
    425              u'UL OL LI.red': (0,0,1,3),
    426              u'LI.red.level': (0,0,2,1),
    427              u'#s12:not(FOO)': (0,1,0,1),
    428              u'button:not([DISABLED])': (0,0,1,1), #?
    429              u'*:not(FOO)': (0,0,0,1),
    430
    431              # elements
    432              u'a+b': (0,0,0,2),
    433              u'a>b': (0,0,0,2),
    434              u'a b': (0,0,0,2),
    435              u'* a': (0,0,0,1),
    436              u'a *': (0,0,0,1),
    437              u'a * b': (0,0,0,2),
    438
    439              u'a:hover': (0,0,0,1),
    440
    441              u'a:first-line': (0,0,0,2),
    442              u'a:first-letter': (0,0,0,2),
    443              u'a:before': (0,0,0,2),
    444              u'a:after': (0,0,0,2),
    445
    446              # classes and attributes
    447              u'.a': (0,0,1,0),
    448              u'*.a': (0,0,1,0),
    449              u'a.a': (0,0,1,1),
    450              u'.a.a': (0,0,2,0), # IE<7 False (0,0,1,0)
    451              u'a.a.a': (0,0,2,1),
    452              u'.a.b': (0,0,2,0),
    453              u'a.a.b': (0,0,2,1),
    454              u'.a .a': (0,0,2,0),
    455              u'*[x]': (0,0,1,0),
    456              u'*[x]': (0,0,1,0),
    457              u'*[x]': (0,0,1,0),
    458              u'*[x=a]': (0,0,1,0),
    459              u'*[x~=a]': (0,0,1,0),
    460              u'*[x|=a]': (0,0,1,0),
    461              u'*[x^=a]': (0,0,1,0),
    462              u'*[x*=a]': (0,0,1,0),
    463              u'*[x$=a]': (0,0,1,0),
    464              u'*[x][y]': (0,0,2,0),
    465
    466              # ids
    467              u'#a': (0,1,0,0),
    468              u'*#a': (0,1,0,0),
    469              u'x#a': (0,1,0,1),
    470              u'.x#a': (0,1,1,0),
    471              u'a.x#a': (0,1,1,1),
    472              u'#a#a': (0,2,0,0), # e.g. html:id + xml:id
    473              u'#a#b': (0,2,0,0),
    474              u'#a #b': (0,2,0,0),
    475              }
    476          for text in tests:
    477              selector.selectorText = text
    478              self.assertEqual(tests[text], selector.specificity)
    479
    480 -    def test_reprANDstr(self):
    481          "Selector.__repr__(), .__str__()"
    482          sel=u'a + b'
    483
    484          s = cssutils.css.Selector(selectorText=sel)
    485
    486          self.assert_(sel in str(s))
    487
    488          s2 = eval(repr(s))
    489          self.assert_(isinstance(s2, s.__class__))
    490          self.assert_(sel == s2.selectorText)
    491
    492
    493  if __name__ == '__main__':
    494      import unittest
    495      unittest.main()
    496