| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import unittest
- import cssbeautifier
- class CSSBeautifierTest(unittest.TestCase):
- def resetOptions(self):
- false = False
- true = True
- self.options = cssbeautifier.default_options()
- self.options.indent_size = 1
- self.options.indent_char = '\t'
- self.options.selector_separator_newline = true
- self.options.end_with_newline = false
- self.options.newline_between_rules = false
- def testGenerated(self):
- self.resetOptions()
- test_fragment = self.decodesto
- t = self.decodesto
- false = False
- true = True
- {{#default_options}} self.options.{{name}} = {{&value}}
- {{/default_options}}
- {{#groups}}
- {{^matrix}}
- # {{&name}}
- {{#options}}
- self.options.{{name}} = {{&value}}
- {{/options}}
- {{#tests}}
- {{#test_line}}.{{/test_line}}
- {{/tests}}
- {{/matrix}}
- {{#matrix}}
- # {{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})
- {{#options}}
- self.options.{{name}} = {{&value}}
- {{/options}}
- {{#tests}}
- {{#test_line}}.{{/test_line}}
- {{/tests}}
- {{/matrix}}
- {{/groups}}
- def testNewline(self):
- self.resetOptions()
- t = self.decodesto
- self.options.end_with_newline = True
- t("", "\n")
- t("\n", "\n")
- t(".tabs{}\n", ".tabs {}\n")
- t(".tabs{}", ".tabs {}\n")
- def testBasics(self):
- self.resetOptions()
- t = self.decodesto
- t("", "")
- t("\n", "")
- t(".tabs{}\n", ".tabs {}")
- t(".tabs{}", ".tabs {}")
- t(".tabs{color:red}", ".tabs {\n\tcolor: red\n}")
- t(".tabs{color:rgb(255, 255, 0)}", ".tabs {\n\tcolor: rgb(255, 255, 0)\n}")
- t(".tabs{background:url('back.jpg')}", ".tabs {\n\tbackground: url('back.jpg')\n}")
- t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}")
- t("@media print {.tab{}}", "@media print {\n\t.tab {}\n}")
- t("@media print {.tab{background-image:url(foo@2x.png)}}", "@media print {\n\t.tab {\n\t\tbackground-image: url(foo@2x.png)\n\t}\n}")
- t("a:before {\n" +
- "\tcontent: 'a{color:black;}\"\"\\'\\'\"\\n\\n\\na{color:black}\';\n" +
- "}");
- # may not eat the space before "["
- t('html.js [data-custom="123"] {\n\topacity: 1.00;\n}')
- t('html.js *[data-custom="123"] {\n\topacity: 1.00;\n}')
- # lead-in whitespace determines base-indent.
- # lead-in newlines are stripped.
- t("\n\na, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}")
- t(" a, img {padding: 0.2px}", " a,\n img {\n \tpadding: 0.2px\n }")
- t(" \t \na, img {padding: 0.2px}", " \t a,\n \t img {\n \t \tpadding: 0.2px\n \t }")
- t("\n\n a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}")
- def testSeperateSelectors(self):
- self.resetOptions()
- t = self.decodesto
- t("#bla, #foo{color:red}", "#bla,\n#foo {\n\tcolor: red\n}")
- t("a, img {padding: 0.2px}", "a,\nimg {\n\tpadding: 0.2px\n}")
- def testBlockNesting(self):
- self.resetOptions()
- t = self.decodesto
- t("#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}")
- t("@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: 'Bitstream Vera Serif Bold';\n\t\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n\t}\n}")
- # @font-face {
- # font-family: 'Bitstream Vera Serif Bold';
- # src: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');
- # }
- # @media screen {
- # #foo:hover {
- # background-image: url(foo.png);
- # }
- # @media screen and (min-device-pixel-ratio: 2) {
- # @font-face {
- # font-family: 'Helvetica Neue'
- # }
- # #foo:hover {
- # background-image: url(foo@2x.png);
- # }
- # }
- # }
- t("@font-face {\n\tfont-family: 'Bitstream Vera Serif Bold';\n\tsrc: url('http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf');\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: 'Helvetica Neue'\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}")
- def testOptions(self):
- self.resetOptions()
- self.options.indent_size = 2
- self.options.indent_char = ' '
- self.options.selector_separator_newline = False
- t = self.decodesto
- # pseudo-classes and pseudo-elements
- t("#foo:hover {\n background-image: url(foo@2x.png)\n}")
- t("#foo *:hover {\n color: purple\n}")
- t("::selection {\n color: #ff0000;\n}")
- # TODO: don't break nested pseduo-classes
- t("@media screen {.tab,.bat:hover {color:red}}", "@media screen {\n .tab, .bat:hover {\n color: red\n }\n}")
- # particular edge case with braces and semicolons inside tags that allows custom text
- t( "a:not(\"foobar\\\";{}omg\"){\ncontent: 'example\\';{} text';\ncontent: \"example\\\";{} text\";}",
- "a:not(\"foobar\\\";{}omg\") {\n content: 'example\\';{} text';\n content: \"example\\\";{} text\";\n}")
- def testLessCss(self):
- self.resetOptions()
- t = self.decodesto
- t('.well{ \n @well-bg:@bg-color;@well-fg:@fg-color;}','.well {\n\t@well-bg: @bg-color;\n\t@well-fg: @fg-color;\n}')
- t('.well {&.active {\nbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;}}',
- '.well {\n' +
- '\t&.active {\n' +
- '\t\tbox-shadow: 0 1px 1px @border-color, 1px 0 1px @border-color;\n' +
- '\t}\n' +
- '}')
- t('a {\n' +
- '\tcolor: blue;\n' +
- '\t&:hover {\n' +
- '\t\tcolor: green;\n' +
- '\t}\n' +
- '\t& & &&&.active {\n' +
- '\t\tcolor: green;\n' +
- '\t}\n' +
- '}')
- # Not sure if this is sensible
- # but I believe it is correct to not remove the space in "&: hover".
- t('a {\n' +
- '\t&: hover {\n' +
- '\t\tcolor: green;\n' +
- '\t}\n' +
- '}');
- # import
- t('@import "test";');
- # don't break nested pseudo-classes
- t("a:first-child{color:red;div:first-child{color:black;}}",
- "a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}");
- # handle SASS/LESS parent reference
- t("div{&:first-letter {text-transform: uppercase;}}",
- "div {\n\t&:first-letter {\n\t\ttext-transform: uppercase;\n\t}\n}");
- # nested modifiers (&:hover etc)
- t(".tabs{&:hover{width:10px;}}", ".tabs {\n\t&:hover {\n\t\twidth: 10px;\n\t}\n}")
- t(".tabs{&.big{width:10px;}}", ".tabs {\n\t&.big {\n\t\twidth: 10px;\n\t}\n}")
- t(".tabs{&>big{width:10px;}}", ".tabs {\n\t&>big {\n\t\twidth: 10px;\n\t}\n}")
- t(".tabs{&+.big{width:10px;}}", ".tabs {\n\t&+.big {\n\t\twidth: 10px;\n\t}\n}")
- # nested rules
- t(".tabs{.child{width:10px;}}", ".tabs {\n\t.child {\n\t\twidth: 10px;\n\t}\n}")
- # variables
- t("@myvar:10px;.tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}")
- t("@myvar:10px; .tabs{width:10px;}", "@myvar: 10px;\n.tabs {\n\twidth: 10px;\n}")
- def decodesto(self, input, expectation=None):
- if expectation == None:
- expectation = input
- self.assertMultiLineEqual(
- cssbeautifier.beautify(input, self.options), expectation)
- # if the expected is different from input, run it again
- # expected output should be unchanged when run twice.
- if not expectation != input:
- self.assertMultiLineEqual(
- cssbeautifier.beautify(expectation, self.options), expectation)
- # Everywhere we do newlines, they should be replaced with opts.eol
- self.options.eol = '\r\\n';
- expectation = expectation.replace('\n', '\r\n')
- self.assertMultiLineEqual(
- cssbeautifier.beautify(input, self.options), expectation)
- input = input.replace('\n', '\r\n')
- self.assertMultiLineEqual(
- cssbeautifier.beautify(input, self.options), expectation)
- self.options.eol = '\n'
- if __name__ == '__main__':
- unittest.main()
|