"""Tests for css.CSSStyleSheet""" import xml.dom from . import basetest import cssutils.css import pytest class TestCSSStyleSheet(basetest.BaseTestCase): def setup_method(self): self.r = cssutils.css.CSSStyleSheet() # used by basetest self.s = self.r # used here self.rule = cssutils.css.CSSStyleRule() def test_init(self): "CSSStyleSheet.__init__()" assert 'text/css' == self.s.type assert not self.s._readonly assert [] == self.s.cssRules assert not self.s.disabled assert self.s.href is None assert self.s.media is None assert self.s.ownerNode is None assert self.s.parentStyleSheet is None assert '' == self.s.title # check that type is readonly with pytest.raises(AttributeError): self.r.__setattr__('href', 'x') with pytest.raises(AttributeError): self.r.__setattr__('parentStyleSheet', 'x') with pytest.raises(AttributeError): self.r.__setattr__('ownerNode', 'x') with pytest.raises(AttributeError): self.r.__setattr__('type', 'x') def test_iter(self): "CSSStyleSheet.__iter__()" s = cssutils.css.CSSStyleSheet() s.cssText = '''@import "x";@import "y";@namespace "u";''' types = [ cssutils.css.CSSRule.IMPORT_RULE, cssutils.css.CSSRule.IMPORT_RULE, cssutils.css.CSSRule.NAMESPACE_RULE, ] for i, rule in enumerate(s): assert rule == s.cssRules[i] assert rule.type == types[i] def test_refs(self): """CSSStylesheet references""" s = cssutils.parseString('a {}') rules = s.cssRules assert s.cssRules[0].parentStyleSheet == s assert rules[0].parentStyleSheet == s # set cssText s.cssText = 'b{}' # from 0.9.7b1 assert rules != s.cssRules # set cssRules s.cssRules = cssutils.parseString( ''' @charset "ascii"; /**/ @import "x"; @namespace "http://example.com/ns0"; @media all { a { color: green; } } @font-face { font-family: x; } @page { font-family: Arial; } @x; b {}').cssRules''' ).cssRules # new object assert rules != s.cssRules for i, r in enumerate(s.cssRules): assert r.parentStyleSheet == s # namespaces s = cssutils.parseString('@namespace "http://example.com/ns1"; a {}') namespaces = s.namespaces assert list(s.namespaces.items()) == [('', 'http://example.com/ns1')] s.cssText = '@namespace x "http://example.com/ns2"; x|a {}' # not anymore! assert namespaces != s.namespaces assert list(s.namespaces.items()) == [('x', 'http://example.com/ns2')] # variables s = cssutils.parseString('@variables { a:1}') vars1 = s.variables assert vars1['a'] == '1' s = cssutils.parseString('@variables { a:2}') vars2 = s.variables assert vars1 != vars2 assert vars1['a'] == '1' assert vars2['a'] == '2' def test_cssRules(self): "CSSStyleSheet.cssRules" s = cssutils.parseString('/*1*/a {x:1}') assert 2 == s.cssRules.length del s.cssRules[0] assert 1 == s.cssRules.length s.cssRules.append('/*2*/') assert 2 == s.cssRules.length s.cssRules.extend(cssutils.parseString('/*3*/x {y:2}').cssRules) assert 4 == s.cssRules.length assert b'a {\n x: 1\n }\n/*2*/\n/*3*/\nx {\n y: 2\n }' == s.cssText for r in s.cssRules: assert r.parentStyleSheet == s def test_cssText(self): "CSSStyleSheet.cssText" tests = { '': b'', # @charset '@charset "ascii";\n@import "x";': b'@charset "ascii";\n@import "x";', '@charset "ascii";\n@media all {}': b'@charset "ascii";', '@charset "ascii";\n@x;': b'@charset "ascii";\n@x;', '@charset "ascii";\na {\n x: 1\n }': b'@charset "ascii";\na {\n x: 1\n }', # @import '@x;\n@import "x";': b'@x;\n@import "x";', '@import "x";\n@import "y";': b'@import "x";\n@import "y";', '@import "x";\n@media all {}': b'@import "x";', '@import "x";\n@x;': b'@import "x";\n@x;', '@import "x";\na {\n x: 1\n }': b'@import "x";\na {\n x: 1\n }', # @namespace '@x;\n@namespace a "x";': b'@x;\n@namespace a "x";', '@namespace a "x";\n@namespace b "y";': b'@namespace a "x";\n@namespace b "y";', '@import "x";\n@namespace a "x";\n@media all {}': b'@import "x";\n@namespace a "x";', '@namespace a "x";\n@x;': b'@namespace a "x";\n@x;', '@namespace a "x";\na {\n x: 1\n }': b'@namespace a "x";\na {\n x: 1\n }', """@namespace url("e1"); @namespace url("e2"); @namespace x url("x1"); @namespace x url("x2"); test{color: green} x|test {color: green}""": b"""@namespace "e2"; @namespace x "x2"; test { color: green } x|test { color: green }""" # ur'\1 { \2: \3 }': ur'''\x01 { # \x02: \x03 # }''', # ur''' # \@ { \@: \@ } # \1 { \2: \3 } # \{{\::\;;} # ''': ur'''\@ { # \@: \@ # } # \1 { # \2: \3 # } # \{ # {\:: \; # }''' } self.do_equal_r(tests) tests = { '': None, # @charset '@charset "ascii";\n@import "x";': None, '@charset "ascii";\n@media all {}': '@charset "ascii";', '@charset "ascii";\n@x;': None, '@charset "ascii";\na {\n x: 1\n }': None, # @import '@x;\n@import "x";': None, '@import "x";\n@import "y";': None, '@import "x";\n@media all {}': '@import "x";', '@import "x";\n@x;': None, '@import "x";\na {\n x: 1\n }': None, # @namespace '@x;\n@namespace a "x";': None, '@namespace a "x";\n@namespace b "y";': None, '@import "x";\n@namespace a "x";\n@media all {}': '@import "x";\n@namespace a "x";', '@namespace a "x";\n@x;': None, '@namespace a "x";\na {\n x: 1\n }': None, """@namespace url("e1"); @namespace url("e2"); @namespace x url("x1"); @namespace x url("x2"); test{color: green} x|test {color: green}""": """@namespace "e2"; @namespace x "x2"; test { color: green } x|test { color: green }""" # ur'\1 { \2: \3 }': ur'''\x01 { # \x02: \x03 # }''', # ur''' # \@ { \@: \@ } # \1 { \2: \3 } # \{{\::\;;} # ''': ur'''\@ { # \@: \@ # } # \1 { # \2: \3 # } # \{ # {\:: \; # }''' } self.do_equal_p(tests) s = cssutils.css.CSSStyleSheet() s.cssText = '''@charset "ascii";@import "x";@namespace a "x"; @media all {/*1*/}@page {margin: 0}a {\n x: 1\n }@unknown;/*comment*/''' for r in s.cssRules: assert s == r.parentStyleSheet def test_cssText_HierarchyRequestErr(self): "CSSStyleSheet.cssText HierarchyRequestErr" tests = { # @charset: only one and always 1st ' @charset "utf-8";': xml.dom.HierarchyRequestErr, '@charset "ascii";@charset "ascii";': xml.dom.HierarchyRequestErr, '/*c*/@charset "ascii";': xml.dom.HierarchyRequestErr, '@import "x"; @charset "ascii";': xml.dom.HierarchyRequestErr, '@namespace a "x"; @charset "ascii";': xml.dom.HierarchyRequestErr, '@media all {} @charset "ascii";': xml.dom.HierarchyRequestErr, '@page {} @charset "ascii";': xml.dom.HierarchyRequestErr, 'a {} @charset "ascii";': xml.dom.HierarchyRequestErr, # @import: before @namespace, @media, @page, sr '@namespace a "x"; @import "x";': xml.dom.HierarchyRequestErr, '@media all {} @import "x";': xml.dom.HierarchyRequestErr, '@page {} @import "x";': xml.dom.HierarchyRequestErr, 'a {} @import "x";': xml.dom.HierarchyRequestErr, # @namespace: before @media, @page, sr '@media all {} @namespace a "x";': xml.dom.HierarchyRequestErr, '@page {} @namespace a "x";': xml.dom.HierarchyRequestErr, 'a {} @namespace a "x";': xml.dom.HierarchyRequestErr, } self.do_raise_r(tests) self.do_raise_p(tests) def test_cssText_SyntaxErr(self): """CSSStyleSheet.cssText SyntaxErr for single {, } or ; """ tests = { '{': xml.dom.SyntaxErr, '}': xml.dom.SyntaxErr, ';': xml.dom.SyntaxErr, '@charset "ascii";{': xml.dom.SyntaxErr, '@charset "ascii";}': xml.dom.SyntaxErr, '@charset "ascii";;': xml.dom.SyntaxErr, } self.do_raise_r(tests) self.do_raise_p(tests) def test_encoding(self): "CSSStyleSheet.encoding" self.s.cssText = '' assert 'utf-8' == self.s.encoding self.s.encoding = 'ascii' assert 'ascii' == self.s.encoding assert 1 == self.s.cssRules.length assert 'ascii' == self.s.cssRules[0].encoding self.s.encoding = None assert 'utf-8' == self.s.encoding assert 0 == self.s.cssRules.length self.s.encoding = 'UTF-8' assert 'utf-8' == self.s.encoding assert 1 == self.s.cssRules.length with pytest.raises(xml.dom.SyntaxErr): self.s._setEncoding('INVALID ENCODING') assert 'utf-8' == self.s.encoding assert 1 == self.s.cssRules.length def test_namespaces1(self): "CSSStyleSheet.namespaces.namespaces" # tests for namespaces internal methods s = cssutils.css.CSSStyleSheet() assert 0 == len(s.namespaces) css = '''@namespace "default"; @namespace ex "example"; @namespace ex2 "example"; ex2|x { top: 0 }''' expcss = '''@namespace "default"; @namespace ex2 "example"; ex2|x { top: 0 }''' s.cssText = css assert s.cssText == expcss.encode() assert s.namespaces.namespaces == {'': 'default', 'ex2': 'example'} # __contains__ assert '' in s.namespaces assert 'ex2' in s.namespaces assert "NOTSET" not in s.namespaces # __delitem__ with pytest.raises(xml.dom.NoModificationAllowedErr): s.namespaces.__delitem__('ex2') s.namespaces['del'] = 'del' del s.namespaces['del'] with pytest.raises(xml.dom.NamespaceErr): s.namespaces.__getitem__('del') # __getitem__ assert 'default' == s.namespaces[''] assert 'example' == s.namespaces['ex2'] with pytest.raises(xml.dom.NamespaceErr): s.namespaces.__getitem__('UNSET') # __iter__ assert ['', 'ex2'] == sorted(list(s.namespaces)) # __len__ assert 2 == len(s.namespaces) # __setitem__ with pytest.raises(xml.dom.NoModificationAllowedErr): s.namespaces.__setitem__('ex2', 'NEWURI') s.namespaces['n1'] = 'new' assert s.namespaces.namespaces == {'': 'default', 'ex2': 'example', 'n1': 'new'} s.namespaces['n'] = 'new' # replaces prefix! assert s.namespaces.namespaces == {'': 'default', 'ex2': 'example', 'n': 'new'} # prefixForNamespaceURI assert '' == s.namespaces.prefixForNamespaceURI('default') assert 'ex2' == s.namespaces.prefixForNamespaceURI('example') with pytest.raises(IndexError): s.namespaces.prefixForNamespaceURI('UNSET') # .keys assert set(s.namespaces.keys()) == {'', 'ex2', 'n'} # .get assert 'x' == s.namespaces.get('UNKNOWN', 'x') assert 'example' == s.namespaces.get('ex2', 'not used defa') def test_namespaces2(self): "CSSStyleSheet.namespaces" # tests using CSSStyleSheet.namespaces s = cssutils.css.CSSStyleSheet() css = '@namespace n "new";' # doubles will be removed s.insertRule(css + css) assert s.cssText == css.encode() r = cssutils.css.CSSNamespaceRule(prefix='ex2', namespaceURI='example') s.insertRule(r) r = cssutils.css.CSSNamespaceRule(namespaceURI='default') s.insertRule(r) expcss = '''@namespace n "new"; @namespace ex2 "example"; @namespace "default";''' assert s.cssText == expcss.encode() r.prefix = 'DEFAULT' expcss = '''@namespace n "new"; @namespace ex2 "example"; @namespace DEFAULT "default";''' assert s.cssText == expcss.encode() # CSSMediaRule with pytest.raises(xml.dom.NamespaceErr): s.add('@media all {x|a {left: 0}}') mcss = '@media all {\n ex2|SEL1 {\n left: 0\n }\n }' s.add(mcss) expcss += '\n' + mcss assert s.cssText == expcss.encode() # CSSStyleRule with pytest.raises(xml.dom.NamespaceErr): s.add('x|a {top: 0}') scss = 'n|SEL2 {\n top: 0\n }' s.add(scss) expcss += '\n' + scss assert s.cssText == expcss.encode() mr = s.cssRules[3] sr = s.cssRules[4] # SelectorList @media with pytest.raises(xml.dom.NamespaceErr): mr.cssRules[0]._setSelectorText('x|b') oldsel, newsel = mr.cssRules[0].selectorText, 'n|SEL3, a' mr.cssRules[0].selectorText = newsel expcss = expcss.replace(oldsel, newsel) assert s.cssText == expcss.encode() # SelectorList stylerule with pytest.raises(xml.dom.NamespaceErr): sr._setSelectorText('x|b') oldsel, newsel = sr.selectorText, 'ex2|SEL4, a' sr.selectorText = newsel expcss = expcss.replace(oldsel, newsel) assert s.cssText == expcss.encode() # Selector @media with pytest.raises(xml.dom.NamespaceErr): mr.cssRules[0].selectorList.append('x|b') oldsel, newsel = mr.cssRules[0].selectorText, 'ex2|SELMR' mr.cssRules[0].selectorList.append(newsel) expcss = expcss.replace(oldsel, oldsel + ', ' + newsel) assert s.cssText == expcss.encode() # Selector stylerule with pytest.raises(xml.dom.NamespaceErr): sr.selectorList.append('x|b') oldsel, newsel = sr.selectorText, 'ex2|SELSR' sr.selectorList.append(newsel) expcss = expcss.replace(oldsel, oldsel + ', ' + newsel) assert s.cssText == expcss.encode() assert ( s.cssText == b'''@namespace n "new"; @namespace ex2 "example"; @namespace DEFAULT "default"; @media all { n|SEL3, a, ex2|SELMR { left: 0 } } ex2|SEL4, a, ex2|SELSR { top: 0 }''' ) def test_namespaces3(self): "CSSStyleSheet.namespaces 3" # tests setting namespaces with new {} s = cssutils.css.CSSStyleSheet() css = 'h|a { top: 0 }' with pytest.raises(xml.dom.NamespaceErr): s.add(css) s.add('@namespace x "html";') assert s.namespaces['x'] == 'html' r = cssutils.css.CSSStyleRule() r.cssText = (css, {'h': 'html'}) s.add(r) # uses x as set before! h is temporary only assert s.cssText == b'@namespace x "html";\nx|a {\n top: 0\n }' # prefix is now "x"! with pytest.raises(xml.dom.NamespaceErr): r.selectorList.append('h|b') with pytest.raises(xml.dom.NamespaceErr): r.selectorList.append('y|b') s.namespaces['y'] = 'html' r.selectorList.append('y|b') assert s.cssText == b'@namespace y "html";\ny|a, y|b {\n top: 0\n }' with pytest.raises(xml.dom.NoModificationAllowedErr): s.namespaces.__delitem__('y') assert s.cssText == b'@namespace y "html";\ny|a, y|b {\n top: 0\n }' s.cssRules[0].prefix = '' assert s.cssText == b'@namespace "html";\na, b {\n top: 0\n }' # remove need of namespace s.cssRules[0].prefix = 'x' s.cssRules[1].selectorText = 'a, b' assert s.cssText == b'@namespace x "html";\na, b {\n top: 0\n }' def test_namespaces4(self): "CSSStyleSheet.namespaces 4" # tests setting namespaces with new {} s = cssutils.css.CSSStyleSheet() assert {} == s.namespaces.namespaces s.namespaces.namespaces['a'] = 'no setting possible' assert {} == s.namespaces.namespaces s.namespaces[None] = 'default' assert {'': 'default'} == s.namespaces.namespaces del s.namespaces[''] assert {} == s.namespaces.namespaces s.namespaces[''] = 'default' assert {'': 'default'} == s.namespaces.namespaces del s.namespaces[None] assert {} == s.namespaces.namespaces s.namespaces['p'] = 'uri' # cannot use namespaces.namespaces del s.namespaces.namespaces['p'] assert {'p': 'uri'} == s.namespaces.namespaces with pytest.raises(xml.dom.NamespaceErr, match=r"Prefix undefined not found\."): del s.namespaces['undefined'] def test_namespaces5(self): "CSSStyleSheet.namespaces 5" # unknown namespace s = cssutils.parseString('a|a { color: red }') assert s.cssText == b'' s = cssutils.css.CSSStyleSheet() with pytest.raises(xml.dom.NamespaceErr, match=r"Prefix a not found\."): s._setCssText('a|a { color: red }') def test_deleteRuleIndex(self): "CSSStyleSheet.deleteRule(index)" self.s.cssText = '@charset "ascii"; @import "x"; @x; a {\n x: 1\n }@y;' assert 5 == self.s.cssRules.length with pytest.raises(xml.dom.IndexSizeErr): self.s.deleteRule(5) # end -1 # check parentStyleSheet r = self.s.cssRules[-1] assert self.s == r.parentStyleSheet self.s.deleteRule(-1) assert r.parentStyleSheet is None assert 4 == self.s.cssRules.length assert ( b'@charset "ascii";\n@import "x";\n@x;\na {\n x: 1\n }' == self.s.cssText ) # beginning self.s.deleteRule(0) assert 3 == self.s.cssRules.length assert b'@import "x";\n@x;\na {\n x: 1\n }' == self.s.cssText # middle self.s.deleteRule(1) assert 2 == self.s.cssRules.length assert b'@import "x";\na {\n x: 1\n }' == self.s.cssText # end self.s.deleteRule(1) assert 1 == self.s.cssRules.length assert b'@import "x";' == self.s.cssText def test_deleteRule(self): "CSSStyleSheet.deleteRule(rule)" s = cssutils.css.CSSStyleSheet() s.cssText = ''' @namespace x "http://example.com"; a { color: red; } b { color: blue; } c { color: green; } ''' n, s1, s2, s3 = s.cssRules r = cssutils.css.CSSStyleRule() with pytest.raises(xml.dom.IndexSizeErr): s.deleteRule(r) assert 4 == s.cssRules.length s.deleteRule(n) assert 3 == s.cssRules.length assert ( s.cssText == b'a {\n color: red\n }\nb {\n color: blue\n }\nc {\n color: green\n }' ) with pytest.raises(xml.dom.IndexSizeErr): s.deleteRule(n) s.deleteRule(s2) assert 2 == s.cssRules.length assert s.cssText == b'a {\n color: red\n }\nc {\n color: green\n }' with pytest.raises(xml.dom.IndexSizeErr): s.deleteRule(s2) def _gets(self): # complete self.cr = cssutils.css.CSSCharsetRule('ascii') self.c = cssutils.css.CSSComment('/*c*/') self.ur = cssutils.css.CSSUnknownRule('@x;') self.ir = cssutils.css.CSSImportRule('x') self.nr = cssutils.css.CSSNamespaceRule('uri', 'p') self.mr = cssutils.css.CSSMediaRule() self.mr.cssText = '@media all { @m; }' self.pr = cssutils.css.CSSPageRule() self.pr.style = 'margin: 0;' self.sr = cssutils.css.CSSStyleRule() self.sr.cssText = 'a {\n x: 1\n }' s = cssutils.css.CSSStyleSheet() s.insertRule(self.cr) # 0 s.insertRule(self.ir) # 1 s.insertRule(self.nr) # 2 s.insertRule(self.mr) # 3 s.insertRule(self.sr) # 4 s.insertRule(self.mr) # 5 s.insertRule(self.pr) # 6 s.insertRule(self.sr) # 7 assert ( b'@charset "ascii";\n@import url(x);\n@namespace p "uri";\n@media all {\n @m;\n }\na {\n x: 1\n }\n@media all {\n @m;\n }\n@page {\n margin: 0\n }\na {\n x: 1\n }' == s.cssText ) return s, s.cssRules.length def test_add(self): "CSSStyleSheet.add()" full = cssutils.css.CSSStyleSheet() sheet = cssutils.css.CSSStyleSheet() css = [ '@charset "ascii";', '@import "x";', '@namespace p "u";', '@page {\n left: 0\n }', '@font-face {\n src: local(x)\n }', '@media all {\n a {\n color: red\n }\n }', 'a {\n color: green\n }', '/*comment*/', '@x;', ] fullcss = '\n'.join(css) full.cssText = fullcss assert full.cssText == fullcss.encode() for i, line in enumerate(css): # sheet without same ruletype before = css[:i] after = css[i + 1 :] sheet.cssText = ''.join(before + after) index = sheet.add(line) if i < 3: # specific insertion point assert fullcss.encode() == sheet.cssText assert i == index else: # end of sheet expected = before expected.extend(after) expected.append(line) assert '\n'.join(expected).encode() == sheet.cssText assert len(expected) - 1 == index # no same rule present # sheet with the same ruletype if i == 1: line = '@import "x2";' if i == 2: line = '@namespace p2 "u2";' full.cssText = fullcss index = full.add(line) if i < 1: assert fullcss.encode() == sheet.cssText assert i == index # no same rule present else: if i < 3: # in order expected = css[: i + 1] # including same rule expected.append(line) expected.extend(css[i + 1 :]) expectedindex = i + 1 else: # just appended as no order needed expected = css[:] expected.append(line) expectedindex = len(expected) - 1 assert '\n'.join(expected).encode() == full.cssText assert expectedindex == index # no same rule present def test_addimport(self): p = cssutils.CSSParser(fetcher=lambda url: (None, '/**/')) cssrulessheet = p.parseString('@import "example.css";') imports = ( '@import "example.css";', # string cssutils.css.CSSImportRule(href="example.css"), # CSSRule cssrulessheet.cssRules, # CSSRuleList ) for imp in imports: sheet = p.parseString('', href='http://example.com') sheet.add(imp) added = sheet.cssRules[0] assert sheet == added.parentStyleSheet assert 'example.css' == added.href assert 'utf-8' == added.styleSheet.encoding assert b'/**/' == added.styleSheet.cssText cssrulessheet = p.parseString('@import "example.css";') imports = ( ('@import "example.css";', 'ascii'), # string (cssutils.css.CSSImportRule(href="example.css"), 'ascii'), # CSSRule # got encoding from old parent already (cssrulessheet.cssRules, 'utf-8'), # CSSRuleList ) for imp, enc in imports: sheet = p.parseString('', href='http://example.com', encoding='ascii') sheet.add(imp) added = sheet.cssRules[1] assert sheet == added.parentStyleSheet assert 'example.css' == added.href assert enc == added.styleSheet.encoding if enc == 'ascii': assert b'@charset "ascii";\n/**/' == added.styleSheet.cssText else: assert b'/**/' == added.styleSheet.cssText # if styleSheet is already there encoding is not set new impsheet = p.parseString('@import "example.css";') imp = impsheet.cssRules[0] sheet = p.parseString('', href='http://example.com', encoding='ascii') sheet.add(imp) added = sheet.cssRules[1] assert sheet == added.parentStyleSheet assert 'example.css' == added.href assert 'utf-8' == added.styleSheet.encoding assert b'/**/' == added.styleSheet.cssText def test_insertRule(self): "CSSStyleSheet.insertRule()" s, L = self._gets() # INVALID index with pytest.raises(xml.dom.IndexSizeErr): s.insertRule(self.sr, -1) with pytest.raises(xml.dom.IndexSizeErr): s.insertRule(self.sr, s.cssRules.length + 1) # check if rule is really not in assert L == s.cssRules.length # insert string s.insertRule('a {}') assert L + 1 == s.cssRules.length # insert rule s.insertRule(self.sr) assert L + 2 == s.cssRules.length # insert rulelist s2, L2 = self._gets() rulelist = s2.cssRules del rulelist[:-2] s.insertRule(rulelist) assert L + 2 + 2 == s.cssRules.length def _insertRule(self, rules, notbefore, notafter, anywhere, checkdoubles=True): """ helper test if any rule in rules cannot be inserted before rules in before or after rules in after but before and after rules in anywhere """ for rule in rules: for r in notbefore: s = cssutils.css.CSSStyleSheet() s.insertRule(r) with pytest.raises(xml.dom.HierarchyRequestErr): s.insertRule(rule, 0) s = cssutils.css.CSSStyleSheet() s.add(r) with pytest.raises(xml.dom.HierarchyRequestErr): s.insertRule(rule, 0) for r in notafter: s = cssutils.css.CSSStyleSheet() s.insertRule(r) with pytest.raises(xml.dom.HierarchyRequestErr): s.insertRule(rule, 1) s = cssutils.css.CSSStyleSheet() s.add(r) s.add(rule) # never raises assert s == r.parentStyleSheet for r in anywhere: s = cssutils.css.CSSStyleSheet() s.insertRule(r) s.insertRule(rule, 0) # before s.insertRule(rule) # after if checkdoubles: assert s.cssRules.length == 3 assert s == r.parentStyleSheet def test_insertRule_charset(self): "CSSStyleSheet.insertRule(@charset)" s, L = self._gets() notbefore = (self.cr,) notafter = ( self.cr, self.ir, self.nr, self.mr, self.pr, self.sr, self.c, self.ur, ) anywhere = () self._insertRule((self.cr,), notbefore, notafter, anywhere) def test_insertRule_import(self): "CSSStyleSheet.insertRule(@import)" s, L = self._gets() notbefore = (self.cr,) notafter = (self.nr, self.pr, self.mr, self.sr) anywhere = (self.c, self.ur, self.ir) self._insertRule((self.ir,), notbefore, notafter, anywhere) def test_insertRule_namespace(self): "CSSStyleSheet.insertRule(@namespace)" s, L = self._gets() notbefore = (self.cr, self.ir) notafter = (self.pr, self.mr, self.sr) anywhere = (self.c, self.ur, self.nr) self._insertRule((self.nr,), notbefore, notafter, anywhere, checkdoubles=False) def test_insertRule_media_page_style(self): "CSSStyleSheet.insertRule(@media, @page, stylerule)" s, L = self._gets() notbefore = (self.cr, self.ir, self.nr) notafter = () anywhere = (self.c, self.ur, self.mr, self.pr, self.sr) self._insertRule((self.pr, self.mr, self.sr), notbefore, notafter, anywhere) def test_insertRule_unknownandcomment(self): "CSSStyleSheet.insertRule(@ unknown, comment)" s, L = self._gets() notbefore = (self.cr,) notafter = () anywhere = (self.c, self.ur, self.ir, self.nr, self.mr, self.pr, self.sr) self._insertRule((self.ur,), notbefore, notafter, anywhere) def test_HTMLComments(self): "CSSStyleSheet CDO CDC" css = '''body { color: red } body { color: blue } body { color: pink } body { color: green } ''' exp = '''body { color: red } body { color: pink }''' sheet = cssutils.parseString(css) assert sheet.cssText == exp.encode() def test_incomplete(self): "CSSStyleRule (incomplete)" tests = { '@import "a': '@import "a";', # no } 'a { x: 1': 'a {\n x: 1\n }', # no } 'a { font-family: "arial sans': 'a {\n font-family: "arial sans"\n }', # no " } self.do_equal_p(tests) # parse def test_NoModificationAllowedErr(self): "CSSStyleSheet NoModificationAllowedErr" css = cssutils.css.CSSStyleSheet(readonly=True) assert css._readonly # internal... with pytest.raises(xml.dom.NoModificationAllowedErr): css._setCssText('@x;') with pytest.raises(xml.dom.NoModificationAllowedErr): css.insertRule(self.rule) with pytest.raises(xml.dom.NoModificationAllowedErr): css.insertRule(self.rule, 0) with pytest.raises(xml.dom.NoModificationAllowedErr): css.deleteRule(0) def test_reprANDstr(self): "CSSStyleSheet.__repr__(), .__str__()" href = 'file:foo.css' title = 'title-of-css' s = cssutils.css.CSSStyleSheet(href=href, title=title) assert href in str(s) assert title in str(s) s2 = eval(repr(s)) assert isinstance(s2, s.__class__) assert href == s2.href assert title == s2.title def test_valid(self): cases = [ ('body { color: red; }', True), ('body { color: asd; }', False), ('body { foo: 12px; }', False), ] for case, expected in cases: sheet = cssutils.parseString(case) msg = "{!r} should be {}".format(case, 'valid' if expected else 'invalid') assert sheet.valid == expected, msg