aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/tdewolff/parse/css/parse_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tdewolff/parse/css/parse_test.go')
-rw-r--r--vendor/github.com/tdewolff/parse/css/parse_test.go248
1 files changed, 248 insertions, 0 deletions
diff --git a/vendor/github.com/tdewolff/parse/css/parse_test.go b/vendor/github.com/tdewolff/parse/css/parse_test.go
new file mode 100644
index 0000000..33f6f5f
--- /dev/null
+++ b/vendor/github.com/tdewolff/parse/css/parse_test.go
@@ -0,0 +1,248 @@
+package css // import "github.com/tdewolff/parse/css"
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "testing"
+
+ "github.com/tdewolff/parse"
+ "github.com/tdewolff/test"
+)
+
+////////////////////////////////////////////////////////////////
+
+func TestParse(t *testing.T) {
+ var parseTests = []struct {
+ inline bool
+ css string
+ expected string
+ }{
+ {true, " x : y ; ", "x:y;"},
+ {true, "color: red;", "color:red;"},
+ {true, "color : red;", "color:red;"},
+ {true, "color: red; border: 0;", "color:red;border:0;"},
+ {true, "color: red !important;", "color:red!important;"},
+ {true, "color: red ! important;", "color:red!important;"},
+ {true, "white-space: -moz-pre-wrap;", "white-space:-moz-pre-wrap;"},
+ {true, "display: -moz-inline-stack;", "display:-moz-inline-stack;"},
+ {true, "x: 10px / 1em;", "x:10px/1em;"},
+ {true, "x: 1em/1.5em \"Times New Roman\", Times, serif;", "x:1em/1.5em \"Times New Roman\",Times,serif;"},
+ {true, "x: hsla(100,50%, 75%, 0.5);", "x:hsla(100,50%,75%,0.5);"},
+ {true, "x: hsl(100,50%, 75%);", "x:hsl(100,50%,75%);"},
+ {true, "x: rgba(255, 238 , 221, 0.3);", "x:rgba(255,238,221,0.3);"},
+ {true, "x: 50vmax;", "x:50vmax;"},
+ {true, "color: linear-gradient(to right, black, white);", "color:linear-gradient(to right,black,white);"},
+ {true, "color: calc(100%/2 - 1em);", "color:calc(100%/2 - 1em);"},
+ {true, "color: calc(100%/2--1em);", "color:calc(100%/2--1em);"},
+ {false, "<!-- @charset; -->", "<!--@charset;-->"},
+ {false, "@media print, screen { }", "@media print,screen{}"},
+ {false, "@media { @viewport ; }", "@media{@viewport;}"},
+ {false, "@keyframes 'diagonal-slide' { from { left: 0; top: 0; } to { left: 100px; top: 100px; } }", "@keyframes 'diagonal-slide'{from{left:0;top:0;}to{left:100px;top:100px;}}"},
+ {false, "@keyframes movingbox{0%{left:90%;}50%{left:10%;}100%{left:90%;}}", "@keyframes movingbox{0%{left:90%;}50%{left:10%;}100%{left:90%;}}"},
+ {false, ".foo { color: #fff;}", ".foo{color:#fff;}"},
+ {false, ".foo { ; _color: #fff;}", ".foo{_color:#fff;}"},
+ {false, "a { color: red; border: 0; }", "a{color:red;border:0;}"},
+ {false, "a { color: red; border: 0; } b { padding: 0; }", "a{color:red;border:0;}b{padding:0;}"},
+ {false, "/* comment */", "/* comment */"},
+
+ // extraordinary
+ {true, "color: red;;", "color:red;"},
+ {true, "color:#c0c0c0", "color:#c0c0c0;"},
+ {true, "background:URL(x.png);", "background:URL(x.png);"},
+ {true, "filter: progid : DXImageTransform.Microsoft.BasicImage(rotation=1);", "filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);"},
+ {true, "/*a*/\n/*c*/\nkey: value;", "key:value;"},
+ {true, "@-moz-charset;", "@-moz-charset;"},
+ {true, "--custom-variable: (0;) ;", "--custom-variable: (0;) ;"},
+ {false, "@import;@import;", "@import;@import;"},
+ {false, ".a .b#c, .d<.e { x:y; }", ".a .b#c,.d<.e{x:y;}"},
+ {false, ".a[b~=c]d { x:y; }", ".a[b~=c]d{x:y;}"},
+ // {false, "{x:y;}", "{x:y;}"},
+ {false, "a{}", "a{}"},
+ {false, "a,.b/*comment*/ {x:y;}", "a,.b{x:y;}"},
+ {false, "a,.b/*comment*/.c {x:y;}", "a,.b.c{x:y;}"},
+ {false, "a{x:; z:q;}", "a{x:;z:q;}"},
+ {false, "@font-face { x:y; }", "@font-face{x:y;}"},
+ {false, "a:not([controls]){x:y;}", "a:not([controls]){x:y;}"},
+ {false, "@document regexp('https:.*') { p { color: red; } }", "@document regexp('https:.*'){p{color:red;}}"},
+ {false, "@media all and ( max-width:400px ) { }", "@media all and (max-width:400px){}"},
+ {false, "@media (max-width:400px) { }", "@media(max-width:400px){}"},
+ {false, "@media (max-width:400px)", "@media(max-width:400px);"},
+ {false, "@font-face { ; font:x; }", "@font-face{font:x;}"},
+ {false, "@-moz-font-face { ; font:x; }", "@-moz-font-face{font:x;}"},
+ {false, "@unknown abc { {} lala }", "@unknown abc{{}lala}"},
+ {false, "a[x={}]{x:y;}", "a[x={}]{x:y;}"},
+ {false, "a[x=,]{x:y;}", "a[x=,]{x:y;}"},
+ {false, "a[x=+]{x:y;}", "a[x=+]{x:y;}"},
+ {false, ".cla .ss > #id { x:y; }", ".cla .ss>#id{x:y;}"},
+ {false, ".cla /*a*/ /*b*/ .ss{}", ".cla .ss{}"},
+ {false, "a{x:f(a(),b);}", "a{x:f(a(),b);}"},
+ {false, "a{x:y!z;}", "a{x:y!z;}"},
+ {false, "[class*=\"column\"]+[class*=\"column\"]:last-child{a:b;}", "[class*=\"column\"]+[class*=\"column\"]:last-child{a:b;}"},
+ {false, "@media { @viewport }", "@media{@viewport;}"},
+ {false, "table { @unknown }", "table{@unknown;}"},
+
+ // early endings
+ {false, "selector{", "selector{"},
+ {false, "@media{selector{", "@media{selector{"},
+
+ // bad grammar
+ {true, "~color:red", "~color:red;"},
+ {false, ".foo { *color: #fff;}", ".foo{*color:#fff;}"},
+ {true, "*color: red; font-size: 12pt;", "*color:red;font-size:12pt;"},
+ {true, "_color: red; font-size: 12pt;", "_color:red;font-size:12pt;"},
+
+ // issues
+ {false, "@media print {.class{width:5px;}}", "@media print{.class{width:5px;}}"}, // #6
+ {false, ".class{width:calc((50% + 2em)/2 + 14px);}", ".class{width:calc((50% + 2em)/2 + 14px);}"}, // #7
+ {false, ".class [c=y]{}", ".class [c=y]{}"}, // tdewolff/minify#16
+ {false, "table{font-family:Verdana}", "table{font-family:Verdana;}"}, // tdewolff/minify#22
+
+ // go-fuzz
+ {false, "@-webkit-", "@-webkit-;"},
+ }
+ for _, tt := range parseTests {
+ t.Run(tt.css, func(t *testing.T) {
+ output := ""
+ p := NewParser(bytes.NewBufferString(tt.css), tt.inline)
+ for {
+ grammar, _, data := p.Next()
+ data = parse.Copy(data)
+ if grammar == ErrorGrammar {
+ if err := p.Err(); err != io.EOF {
+ for _, val := range p.Values() {
+ data = append(data, val.Data...)
+ }
+ if perr, ok := err.(*parse.Error); ok && perr.Message == "unexpected token in declaration" {
+ data = append(data, ";"...)
+ }
+ } else {
+ test.T(t, err, io.EOF)
+ break
+ }
+ } else if grammar == AtRuleGrammar || grammar == BeginAtRuleGrammar || grammar == QualifiedRuleGrammar || grammar == BeginRulesetGrammar || grammar == DeclarationGrammar || grammar == CustomPropertyGrammar {
+ if grammar == DeclarationGrammar || grammar == CustomPropertyGrammar {
+ data = append(data, ":"...)
+ }
+ for _, val := range p.Values() {
+ data = append(data, val.Data...)
+ }
+ if grammar == BeginAtRuleGrammar || grammar == BeginRulesetGrammar {
+ data = append(data, "{"...)
+ } else if grammar == AtRuleGrammar || grammar == DeclarationGrammar || grammar == CustomPropertyGrammar {
+ data = append(data, ";"...)
+ } else if grammar == QualifiedRuleGrammar {
+ data = append(data, ","...)
+ }
+ }
+ output += string(data)
+ }
+ test.String(t, output, tt.expected)
+ })
+ }
+
+ test.T(t, ErrorGrammar.String(), "Error")
+ test.T(t, AtRuleGrammar.String(), "AtRule")
+ test.T(t, BeginAtRuleGrammar.String(), "BeginAtRule")
+ test.T(t, EndAtRuleGrammar.String(), "EndAtRule")
+ test.T(t, BeginRulesetGrammar.String(), "BeginRuleset")
+ test.T(t, EndRulesetGrammar.String(), "EndRuleset")
+ test.T(t, DeclarationGrammar.String(), "Declaration")
+ test.T(t, TokenGrammar.String(), "Token")
+ test.T(t, CommentGrammar.String(), "Comment")
+ test.T(t, CustomPropertyGrammar.String(), "CustomProperty")
+ test.T(t, GrammarType(100).String(), "Invalid(100)")
+}
+
+func TestParseError(t *testing.T) {
+ var parseErrorTests = []struct {
+ inline bool
+ css string
+ col int
+ }{
+ {false, "selector", 9},
+ {true, "color 0", 8},
+ {true, "--color 0", 10},
+ {true, "--custom-variable:0", 0},
+ }
+ for _, tt := range parseErrorTests {
+ t.Run(tt.css, func(t *testing.T) {
+ p := NewParser(bytes.NewBufferString(tt.css), tt.inline)
+ for {
+ grammar, _, _ := p.Next()
+ if grammar == ErrorGrammar {
+ if tt.col == 0 {
+ test.T(t, p.Err(), io.EOF)
+ } else if perr, ok := p.Err().(*parse.Error); ok {
+ test.T(t, perr.Col, tt.col)
+ } else {
+ test.Fail(t, "bad error:", p.Err())
+ }
+ break
+ }
+ }
+ })
+ }
+}
+
+func TestReader(t *testing.T) {
+ input := "x:a;"
+ p := NewParser(test.NewPlainReader(bytes.NewBufferString(input)), true)
+ for {
+ grammar, _, _ := p.Next()
+ if grammar == ErrorGrammar {
+ break
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////
+
+type Obj struct{}
+
+func (*Obj) F() {}
+
+var f1 func(*Obj)
+
+func BenchmarkFuncPtr(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ f1 = (*Obj).F
+ }
+}
+
+var f2 func()
+
+func BenchmarkMemFuncPtr(b *testing.B) {
+ obj := &Obj{}
+ for i := 0; i < b.N; i++ {
+ f2 = obj.F
+ }
+}
+
+func ExampleNewParser() {
+ p := NewParser(bytes.NewBufferString("color: red;"), true) // false because this is the content of an inline style attribute
+ out := ""
+ for {
+ gt, _, data := p.Next()
+ if gt == ErrorGrammar {
+ break
+ } else if gt == AtRuleGrammar || gt == BeginAtRuleGrammar || gt == BeginRulesetGrammar || gt == DeclarationGrammar {
+ out += string(data)
+ if gt == DeclarationGrammar {
+ out += ":"
+ }
+ for _, val := range p.Values() {
+ out += string(val.Data)
+ }
+ if gt == BeginAtRuleGrammar || gt == BeginRulesetGrammar {
+ out += "{"
+ } else if gt == AtRuleGrammar || gt == DeclarationGrammar {
+ out += ";"
+ }
+ } else {
+ out += string(data)
+ }
+ }
+ fmt.Println(out)
+ // Output: color:red;
+}