func TestJS(t *testing.T) { jsTests := []struct { js string expected string }{ {"/*comment*/", ""}, {"// comment\na", "a"}, {"/*! bang comment */", "/*!bang comment*/"}, {"function x(){}", "function x(){}"}, {"function x(a, b){}", "function x(a,b){}"}, {"a b", "a b"}, {"a\n\nb", "a\nb"}, {"a// comment\nb", "a\nb"}, {"''\na", "''\na"}, {"''\n''", "''''"}, {"]\n0", "]\n0"}, {"a\n{", "a\n{"}, {";\na", ";a"}, {",\na", ",a"}, {"}\na", "}\na"}, {"+\na", "+\na"}, {"+\n(", "+\n("}, {"+\n\"\"", "+\"\""}, {"a + ++b", "a+ ++b"}, // JSMin caution {"var a=/\\s?auto?\\s?/i\nvar", "var a=/\\s?auto?\\s?/i\nvar"}, // #14 {"`\n", "`"}, // go fuzz } m := minify.New() for _, tt := range jsTests { r := bytes.NewBufferString(tt.js) w := &bytes.Buffer{} test.Minify(t, tt.js, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestHTMLKeepWhitespace(t *testing.T) { htmlTests := []struct { html string expected string }{ {`cats and dogs `, `cats and dogs`}, {` <div> <i> test </i> <b> test </b> </div> `, `<div> <i> test </i> <b> test </b> </div>`}, {`<strong>x </strong>y`, `<strong>x </strong>y`}, {`<strong>x </strong> y`, `<strong>x </strong> y`}, {"<strong>x </strong>\ny", "<strong>x </strong>\ny"}, {`<p>x </p>y`, `<p>x </p>y`}, {`x <p>y</p>`, `x <p>y`}, {` <!doctype html> <!--comment--> <html> <body><p></p></body></html> `, `<!doctype html><p>`}, // spaces before html and at the start of html are dropped {`<p>x<br> y`, `<p>x<br> y`}, {`<p>x </b> <b> y`, `<p>x </b> <b> y`}, {`a <code>code</code> b`, `a <code>code</code> b`}, {`a <code></code> b`, `a <code></code> b`}, {`a <script>script</script> b`, `a <script>script</script> b`}, {"text\n<!--comment-->\ntext", "text\ntext"}, {"text\n<!--comment-->text<!--comment--> text", "text\ntext text"}, {"abc\n</body>\ndef", "abc\ndef"}, {"<x>\n<!--y-->\n</x>", "<x>\n</x>"}, {"<style>lala{color:red}</style>", "<style>lala{color:red}</style>"}, } m := minify.New() htmlMinifier := &Minifier{KeepWhitespace: true} for _, tt := range htmlTests { r := bytes.NewBufferString(tt.html) w := &bytes.Buffer{} test.Minify(t, tt.html, htmlMinifier.Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestHTMLURL(t *testing.T) { htmlTests := []struct { url string html string expected string }{ {`http://example.com/`, `<a href=http://example.com/>link</a>`, `<a href=//example.com/>link</a>`}, {`https://example.com/`, `<a href=http://example.com/>link</a>`, `<a href=http://example.com/>link</a>`}, {`http://example.com/`, `<a href=https://example.com/>link</a>`, `<a href=https://example.com/>link</a>`}, {`https://example.com/`, `<a href=https://example.com/>link</a>`, `<a href=//example.com/>link</a>`}, {`http://example.com/`, `<a href=" http://example.com ">x</a>`, `<a href=//example.com>x</a>`}, {`http://example.com/`, `<link rel="stylesheet" type="text/css" href="http://example.com">`, `<link rel=stylesheet href=//example.com>`}, {`http://example.com/`, `<!doctype html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head profile="http://dublincore.org/documents/dcq-html/"> <!-- Barlesque 2.75.0 --> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />`, `<!doctype html><html xmlns=//www.w3.org/1999/xhtml xml:lang=en><head profile=//dublincore.org/documents/dcq-html/><meta charset=utf-8>`}, {`http://example.com/`, `<svg xmlns="http://www.w3.org/2000/svg"></svg>`, `<svg xmlns=//www.w3.org/2000/svg></svg>`}, {`https://example.com/`, `<svg xmlns="http://www.w3.org/2000/svg"></svg>`, `<svg xmlns=http://www.w3.org/2000/svg></svg>`}, {`http://example.com/`, `<svg xmlns="https://www.w3.org/2000/svg"></svg>`, `<svg xmlns=https://www.w3.org/2000/svg></svg>`}, {`https://example.com/`, `<svg xmlns="https://www.w3.org/2000/svg"></svg>`, `<svg xmlns=//www.w3.org/2000/svg></svg>`}, } m := minify.New() m.AddFunc("text/html", Minify) for _, tt := range htmlTests { r := bytes.NewBufferString(tt.html) w := &bytes.Buffer{} m.URL, _ = url.Parse(tt.url) test.Minify(t, tt.html, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestDataURI(t *testing.T) { dataURITests := []struct { dataURI string expected string }{ {"data:,text", "data:,text"}, {"data:text/plain;charset=us-ascii,text", "data:,text"}, {"data:TEXT/PLAIN;CHARSET=US-ASCII,text", "data:,text"}, {"data:text/plain;charset=us-asciiz,text", "data:;charset=us-asciiz,text"}, {"data:;base64,dGV4dA==", "data:,text"}, {"data:text/svg+xml;base64,PT09PT09", "data:text/svg+xml;base64,PT09PT09"}, {"data:text/xml;version=2.0,content", "data:text/xml;version=2.0,content"}, {"data:text/xml; version = 2.0,content", "data:text/xml;version=2.0,content"}, {"data:,=====", "data:,%3D%3D%3D%3D%3D"}, {"data:,======", "data:;base64,PT09PT09"}, {"data:text/x,<?x?>", "data:text/x,%3C%3Fx%3F%3E"}, } m := New() m.AddFunc("text/x", func(_ *M, w io.Writer, r io.Reader, _ map[string]string) error { b, _ := ioutil.ReadAll(r) test.String(t, string(b), "<?x?>") w.Write(b) return nil }) for _, tt := range dataURITests { test.Minify(t, tt.dataURI, nil, string(DataURI(m, []byte(tt.dataURI))), tt.expected) } }
func TestContentType(t *testing.T) { contentTypeTests := []struct { contentType string expected string }{ {"text/html", "text/html"}, {"text/html; charset=UTF-8", "text/html;charset=utf-8"}, {"text/html; charset=UTF-8 ; param = \" ; \"", "text/html;charset=utf-8;param=\" ; \""}, {"text/html, text/css", "text/html,text/css"}, } for _, tt := range contentTypeTests { test.Minify(t, tt.contentType, nil, string(ContentType([]byte(tt.contentType))), tt.expected) } }
func TestSVGDecimals(t *testing.T) { var svgTests = []struct { svg string expected string }{ {`<svg x="1.234" y="0.001" width="1.001"><path/></svg>`, `<svg x="1.2" width="1"><path/></svg>`}, } m := minify.New() o := &Minifier{Decimals: 1} for _, tt := range svgTests { r := bytes.NewBufferString(tt.svg) w := &bytes.Buffer{} test.Minify(t, tt.svg, o.Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestSpecialTagClosing(t *testing.T) { m := minify.New() m.AddFunc("text/html", Minify) m.AddFunc("text/css", func(_ *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { b, err := ioutil.ReadAll(r) test.Error(t, err, nil) test.String(t, string(b), "</script>") _, err = w.Write(b) return err }) html := `<style></script></style>` r := bytes.NewBufferString(html) w := &bytes.Buffer{} test.Minify(t, html, Minify(m, w, r, nil), w.String(), html) }
func TestJSON(t *testing.T) { jsonTests := []struct { json string expected string }{ {"{ \"a\": [1, 2] }", "{\"a\":[1,2]}"}, {"[{ \"a\": [{\"x\": null}, true] }]", "[{\"a\":[{\"x\":null},true]}]"}, {"{ \"a\": 1, \"b\": 2 }", "{\"a\":1,\"b\":2}"}, } m := minify.New() for _, tt := range jsonTests { r := bytes.NewBufferString(tt.json) w := &bytes.Buffer{} test.Minify(t, tt.json, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestSVGStyle(t *testing.T) { svgTests := []struct { svg string expected string }{ {`<style> a > b {} </style>`, `<style>a>b{}</style>`}, {`<style> <![CDATA[ @media x < y {} ]]> </style>`, `<style>@media x < y{}</style>`}, {`<style> <![CDATA[ * { content: '<<<<<'; } ]]> </style>`, `<style><![CDATA[*{content:'<<<<<'}]]></style>`}, {`<style/><![CDATA[ * { content: '<<<<<'; ]]>`, `<style/><![CDATA[ * { content: '<<<<<'; ]]>`}, {`<path style="fill: black; stroke: #ff0000;"/>`, `<path style="fill:#000;stroke:red"/>`}, } m := minify.New() m.AddFunc("text/css", css.Minify) for _, tt := range svgTests { r := bytes.NewBufferString(tt.svg) w := &bytes.Buffer{} test.Minify(t, tt.svg, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestCSS(t *testing.T) { cssTests := []struct { css string expected string }{ {"/*comment*/", ""}, {"/*! bang comment */", "/*!bang comment*/"}, {"i{}/*! bang comment */", "i{}/*!bang comment*/"}, {"i { key: value; key2: value; }", "i{key:value;key2:value}"}, {".cla .ss > #id { x:y; }", ".cla .ss>#id{x:y}"}, {".cla[id ^= L] { x:y; }", ".cla[id^=L]{x:y}"}, {"area:focus { outline : 0;}", "area:focus{outline:0}"}, {"@import 'file';", "@import 'file'"}, {"@font-face { x:y; }", "@font-face{x:y}"}, {"input[type=\"radio\"]{x:y}", "input[type=radio]{x:y}"}, {"DIV{margin:1em}", "div{margin:1em}"}, {".CLASS{margin:1em}", ".CLASS{margin:1em}"}, {"@MEDIA all{}", "@media all{}"}, {"@media only screen and (max-width : 800px){}", "@media only screen and (max-width:800px){}"}, {"@media (-webkit-min-device-pixel-ratio:1.5),(min-resolution:1.5dppx){}", "@media(-webkit-min-device-pixel-ratio:1.5),(min-resolution:1.5dppx){}"}, {"[class^=icon-] i[class^=icon-],i[class*=\" icon-\"]{x:y}", "[class^=icon-] i[class^=icon-],i[class*=\" icon-\"]{x:y}"}, {"html{line-height:1;}html{line-height:1;}", "html{line-height:1}html{line-height:1}"}, {".clearfix { *zoom: 1; }", ".clearfix{*zoom:1}"}, {"a { b: 1", "a{b:1}"}, // coverage {"a, b + c { x:y; }", "a,b+c{x:y}"}, // go-fuzz {"input[type=\"\x00\"] { a: b\n}.a{}", "input[type=\"\x00\"]{a:b}.a{}"}, {"a{a:)'''", "a{a:)'''}"}, } m := minify.New() for _, tt := range cssTests { r := bytes.NewBufferString(tt.css) w := &bytes.Buffer{} test.Minify(t, tt.css, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestWildcard(t *testing.T) { mimetypeTests := []struct { mimetype string expected string }{ {"type/sub", "type/sub"}, {"type/*", "type/*"}, {"*/*", "*/*"}, {"type/sub2", "type/*"}, {"type2/sub", "*/*"}, {"dummy/charset;charset=UTF-8", "UTF-8"}, {"dummy/charset; charset = UTF-8 ", "UTF-8"}, {"dummy/params;type=type;sub=two2", "type/*"}, } for _, tt := range mimetypeTests { r := bytes.NewBufferString("") w := &bytes.Buffer{} test.Minify(t, tt.mimetype, m.Minify(tt.mimetype, w, r), w.String(), tt.expected) } }
func TestXML(t *testing.T) { xmlTests := []struct { xml string expected string }{ {"<!-- comment -->", ""}, {"<A>x</A>", "<A>x</A>"}, {"<a><b>x</b></a>", "<a><b>x</b></a>"}, {"<a><b>x\ny</b></a>", "<a><b>x\ny</b></a>"}, {"<a> <![CDATA[ a ]]> </a>", "<a>a</a>"}, {"<a >a</a >", "<a>a</a>"}, {"<?xml version=\"1.0\" ?>", "<?xml version=\"1.0\"?>"}, {"<x></x>", "<x/>"}, {"<x> </x>", "<x/>"}, {"<x a=\"b\"></x>", "<x a=\"b\"/>"}, {"<x a=\"\"></x>", "<x a=\"\"/>"}, {"<x a=a></x>", "<x a=a/>"}, {"<x a=\" a \n\r\t b \"/>", "<x a=\" a b \"/>"}, {"<x a=\"'b"\"></x>", "<x a=\"'b"\"/>"}, {"<x a=\"""'\"></x>", "<x a='\"\"''/>"}, {"<!DOCTYPE foo SYSTEM \"Foo.dtd\">", "<!DOCTYPE foo SYSTEM \"Foo.dtd\">"}, {"text <!--comment--> text", "text text"}, {"text\n<!--comment-->\ntext", "text\ntext"}, {"<!doctype html>", "<!doctype html=>"}, // bad formatted, doctype must be uppercase and html must have attribute value {"<x>\n<!--y-->\n</x>", "<x></x>"}, {"<style>lala{color:red}</style>", "<style>lala{color:red}</style>"}, {`cats and dogs `, `cats and dogs`}, {`</0`, `</0`}, // go fuzz } m := minify.New() for _, tt := range xmlTests { r := bytes.NewBufferString(tt.xml) w := &bytes.Buffer{} test.Minify(t, tt.xml, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestNumberTruncate(t *testing.T) { numberTests := []struct { number string truncate int expected string }{ {"0.1", 1, ".1"}, {"0.0001", 1, "1e-4"}, {"0.111", 1, ".1"}, {"0.111", 0, "0"}, {"0.075", 1, ".1"}, {"0.025", 1, "0"}, {"9.99", 1, "10"}, {"8.88", 1, "8.9"}, {"8.88", 0, "9"}, {"8.00", 0, "8"}, {".88", 0, "1"}, {"1.234", 1, "1.2"}, } for _, tt := range numberTests { test.Minify(t, tt.number, nil, string(Number([]byte(tt.number), tt.truncate)), tt.expected, "truncate to", tt.truncate) } }
func TestPathData(t *testing.T) { var pathDataTests = []struct { pathData string expected string }{ {"M10 10 20 10", "M10 10H20"}, {"M10 10 10 20", "M10 10V20"}, {"M50 50 100 100", "M50 50l50 50"}, {"m50 50 40 40m50 50", "m50 50 40 40m50 50"}, {"M10 10zM15 15", "M10 10zm5 5"}, {"M50 50H55V55", "M50 50h5v5"}, {"M10 10L11 10 11 11", "M10 10h1v1"}, {"M10 10l1 0 0 1", "M10 10h1v1"}, {"M10 10L11 11 0 0", "M10 10l1 1L0 0"}, {"M246.614 51.028L246.614-5.665 189.922-5.665", "M246.614 51.028V-5.665H189.922"}, {"M100,200 C100,100 250,100 250,200 S400,300 400,200", "M1e2 2e2c0-1e2 150-1e2 150 0s150 1e2 150 0"}, {"M200,300 Q400,50 600,300 T1000,300", "M2e2 3e2q2e2-250 4e2.0t4e2.0"}, {"M300,200 h-150 a150,150 0 1,0 150,-150 z", "M3e2 2e2H150A150 150 0 1 0 3e2 50z"}, {"x5 5L10 10", "L10 10"}, {"M.0.1", "M0 .1"}, {"M200.0.1", "M2e2.1"}, // fuzz {"", ""}, {"ML", ""}, {".8.00c0", ""}, {".1.04h0e6.0e6.0e0.0", "h0 0 0 0"}, {"M.1.0.0.2Z", "M.1.0.0.2z"}, {"A.0.0.0.0.3.2e3.7.0.0.0.0.0.1.3.0.0.0.0.2.3.2.0.0.0.0.20.2e-10.0.0.0.0.0.0.0.0", "A0 0 0 0 .3 2e2.7.0.0.0.0.0.1.3.0.0.0.0.2.3.2.0.0.0.0.2 2e-11.0.0.0.0.0.0.0.0"}, } p := NewPathData(&Minifier{Decimals: -1}) for _, tt := range pathDataTests { test.Minify(t, tt.pathData, nil, string(p.ShortenPathData([]byte(tt.pathData))), tt.expected) } }
func TestXMLKeepWhitespace(t *testing.T) { xmlTests := []struct { xml string expected string }{ {`cats and dogs `, `cats and dogs`}, {` <div> <i> test </i> <b> test </b> </div> `, `<div> <i> test </i> <b> test </b> </div>`}, {"text\n<!--comment-->\ntext", "text\ntext"}, {"text\n<!--comment-->text<!--comment--> text", "text\ntext text"}, {"<x>\n<!--y-->\n</x>", "<x>\n</x>"}, {"<style>lala{color:red}</style>", "<style>lala{color:red}</style>"}, {"<x> <?xml?> </x>", "<x><?xml?> </x>"}, {"<x> <![CDATA[ x ]]> </x>", "<x> x </x>"}, {"<x> <![CDATA[ <<<<< ]]> </x>", "<x><![CDATA[ <<<<< ]]></x>"}, } m := minify.New() xmlMinifier := &Minifier{KeepWhitespace: true} for _, tt := range xmlTests { r := bytes.NewBufferString(tt.xml) w := &bytes.Buffer{} test.Minify(t, tt.xml, xmlMinifier.Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestSVG(t *testing.T) { svgTests := []struct { svg string expected string }{ {`<!-- comment -->`, ``}, {`<!DOCTYPE svg SYSTEM "foo.dtd">`, ``}, {`<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "foo.dtd" [ <!ENTITY x "bar"> ]>`, `<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "foo.dtd" [ <!ENTITY x "bar"> ]>`}, {`<!DOCTYPE svg SYSTEM "foo.dtd">`, ``}, {`<?xml version="1.0" ?>`, ``}, {`<style> <![CDATA[ x ]]> </style>`, `<style>x</style>`}, {`<style> <![CDATA[ <<<< ]]> </style>`, `<style><<<<</style>`}, {`<style> <![CDATA[ <<<<< ]]> </style>`, `<style><![CDATA[ <<<<< ]]></style>`}, {`<style/><![CDATA[ <<<<< ]]>`, `<style/><![CDATA[ <<<<< ]]>`}, {`<svg version="1.0"></svg>`, ``}, {`<svg version="1.1" x="0" y="0px" width="100%" height="100%"><path/></svg>`, `<svg><path/></svg>`}, {`<path x="a"> </path>`, `<path x="a"/>`}, {`<path x=" a "/>`, `<path x="a"/>`}, {"<path x=\" a \n b \"/>", `<path x="a b"/>`}, {`<path x="5.0px" y="0%"/>`, `<path x="5" y="0"/>`}, {`<svg viewBox="5.0px 5px 240IN px"><path/></svg>`, `<svg viewBox="5 5 240in px"><path/></svg>`}, {`<svg viewBox="5.0!5px"><path/></svg>`, `<svg viewBox="5!5px"><path/></svg>`}, {`<path d="M 100 100 L 300 100 L 200 100 z"/>`, `<path d="M1e2 1e2H3e2 2e2z"/>`}, {`<path d="M100 -100M200 300z"/>`, `<path d="M1e2-1e2M2e2 3e2z"/>`}, {`<path d="M0.5 0.6 M -100 0.5z"/>`, `<path d="M.5.6M-1e2.5z"/>`}, {`<path d="M01.0 0.6 z"/>`, `<path d="M1 .6z"/>`}, {`<path d="M20 20l-10-10z"/>`, `<path d="M20 20 10 10z"/>`}, {`<?xml version="1.0" encoding="utf-8"?>`, ``}, {`<svg viewbox="0 0 16 16"><path/></svg>`, `<svg viewbox="0 0 16 16"><path/></svg>`}, {`<g></g>`, ``}, {`<g><path/></g>`, `<path/>`}, {`<g id="a"><g><path/></g></g>`, `<g id="a"><path/></g>`}, {`<path fill="#ffffff"/>`, `<path fill="#fff"/>`}, {`<path fill="#fff"/>`, `<path fill="#fff"/>`}, {`<path fill="white"/>`, `<path fill="#fff"/>`}, {`<path fill="#ff0000"/>`, `<path fill="red"/>`}, {`<line x1="5" y1="10" x2="20" y2="40"/>`, `<path d="M5 10 20 40z"/>`}, {`<rect x="5" y="10" width="20" height="40"/>`, `<path d="M5 10h20v40H5z"/>`}, {`<rect x="-5.669" y="147.402" fill="#843733" width="252.279" height="14.177"/>`, `<path fill="#843733" d="M-5.669 147.402h252.279v14.177H-5.669z"/>`}, {`<rect x="5" y="10" rx="2" ry="3"/>`, `<rect x="5" y="10" rx="2" ry="3"/>`}, {`<rect x="5" y="10" height="40"/>`, ``}, {`<rect x="5" y="10" width="30" height="0"/>`, ``}, {`<polygon points="1,2 3,4"/>`, `<path d="M1 2 3 4z"/>`}, {`<polyline points="1,2 3,4"/>`, `<path d="M1 2 3 4"/>`}, {`<svg contentStyleType="text/json ; charset=iso-8859-1"><style>{a : true}</style></svg>`, `<svg contentStyleType="text/json;charset=iso-8859-1"><style>{a : true}</style></svg>`}, {`<metadata><dc:title /></metadata>`, ``}, // from SVGO {`<!DOCTYPE bla><?xml?><!-- comment --><metadata/>`, ``}, {`<polygon fill="none" stroke="#000" points="-0.1,"/>`, `<polygon fill="none" stroke="#000" points="-0.1,"/>`}, // #45 // go fuzz {`<0 d=09e9.6e-9e0`, `<0 d=""`}, {`<line`, `<line`}, } m := minify.New() for _, tt := range svgTests { r := bytes.NewBufferString(tt.svg) w := &bytes.Buffer{} test.Minify(t, tt.svg, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestHTML(t *testing.T) { htmlTests := []struct { html string expected string }{ {`html`, `html`}, {`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">`, `<!doctype html>`}, {`<!-- comment -->`, ``}, {`<!--[if IE 6]>html<![endif]-->`, `<!--[if IE 6]>html<![endif]-->`}, {`<!--[if IE 6]><!--html--><![endif]-->`, `<!--[if IE 6]><!--html--><![endif]-->`}, {`<!--[if IE 6]><style><!--\ncss\n--></style><![endif]-->`, `<!--[if IE 6]><style><!--\ncss\n--></style><![endif]-->`}, {`<style><!--\ncss\n--></style>`, `<style><!--\ncss\n--></style>`}, {`<style>&</style>`, `<style>&</style>`}, {`<html><head></head><body>x</body></html>`, `x`}, {`<meta http-equiv="content-type" content="text/html; charset=utf-8">`, `<meta charset=utf-8>`}, {`<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />`, `<meta charset=utf-8>`}, {`<meta name="keywords" content="a, b">`, `<meta name=keywords content=a,b>`}, {`<meta name="viewport" content="width = 996" />`, `<meta name=viewport content="width=996">`}, {`<span attr="test"></span>`, `<span attr=test></span>`}, {`<span attr='test'test'></span>`, `<span attr="test'test"></span>`}, {`<span attr="test"test"></span>`, `<span attr='test"test'></span>`}, {`<span attr='test""'&test'></span>`, `<span attr='test""'&test'></span>`}, {`<span attr="test/test"></span>`, `<span attr=test/test></span>`}, {`<span>&</span>`, `<span>&</span>`}, {`<span clear=none method=GET></span>`, `<span></span>`}, {`<span onload="javascript:x;"></span>`, `<span onload=x;></span>`}, {`<span selected="selected"></span>`, `<span selected></span>`}, {`<noscript><html><img id="x"></noscript>`, `<noscript><img id=x></noscript>`}, {`<body id="main"></body>`, `<body id=main>`}, {`<style><![CDATA[x]]></style>`, `<style>x</style>`}, {`<link href="data:text/plain, data">`, `<link href=data:,+data>`}, {`<svg width="100" height="100"><circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /></svg>`, `<svg width=100 height=100><circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /></svg>`}, {`</span >`, `</span>`}, {`<meta name=viewport content="width=0.1, initial-scale=1.0 , maximum-scale=1000">`, `<meta name=viewport content="width=.1,initial-scale=1,maximum-scale=1e3">`}, {`<br/>`, `<br>`}, // increase coverage {`<script style="css">js</script>`, `<script style=css>js</script>`}, {`<meta http-equiv="content-type" content="text/plain, text/html">`, `<meta http-equiv=content-type content=text/plain,text/html>`}, {`<meta http-equiv="content-style-type" content="text/less">`, `<meta http-equiv=content-style-type content=text/less>`}, {`<meta http-equiv="content-style-type" content="text/less; charset=utf-8">`, `<meta http-equiv=content-style-type content="text/less;charset=utf-8">`}, {`<meta http-equiv="content-script-type" content="application/js">`, `<meta http-equiv=content-script-type content=application/js>`}, {`<span attr=""></span>`, `<span attr></span>`}, {`<code>x</code>`, `<code>x</code>`}, {`<p></p><p></p>`, `<p><p>`}, {`<ul><li></li> <li></li></ul>`, `<ul><li><li></ul>`}, {`<p></p><a></a>`, `<p></p><a></a>`}, {`<p></p>x<a></a>`, `<p></p>x<a></a>`}, {`<span style=>`, `<span>`}, {`<button onclick=>`, `<button>`}, // whitespace {`cats and dogs `, `cats and dogs`}, {` <div> <i> test </i> <b> test </b> </div> `, `<div><i>test</i> <b>test</b></div>`}, {`<strong>x </strong>y`, `<strong>x </strong>y`}, {`<strong>x </strong> y`, `<strong>x</strong> y`}, {"<strong>x </strong>\ny", "<strong>x</strong>\ny"}, {`<p>x </p>y`, `<p>x</p>y`}, {`x <p>y</p>`, `x<p>y`}, {` <!doctype html> <!--comment--> <html> <body><p></p></body></html> `, `<!doctype html><p>`}, // spaces before html and at the start of html are dropped {`<p>x<br> y`, `<p>x<br>y`}, {`<p>x </b> <b> y`, `<p>x</b> <b>y`}, {`a <code>code</code> b`, `a <code>code</code> b`}, {`a <code></code> b`, `a <code></code>b`}, {`a <script>script</script> b`, `a <script>script</script>b`}, {"text\n<!--comment-->\ntext", "text\ntext"}, {"abc\n</body>\ndef", "abc\ndef"}, {"<x>\n<!--y-->\n</x>", "<x></x>"}, // from HTML Minifier {`<DIV TITLE="blah">boo</DIV>`, `<div title=blah>boo</div>`}, {"<p title\n\n\t =\n \"bar\">foo</p>", `<p title=bar>foo`}, {`<p class=" foo ">foo bar baz</p>`, `<p class=foo>foo bar baz`}, {`<input maxlength=" 5 ">`, `<input maxlength=5>`}, {`<input type="text">`, `<input>`}, {`<form method="get">`, `<form>`}, {`<script language="Javascript">alert(1)</script>`, `<script>alert(1)</script>`}, {`<script></script>`, ``}, {`<p onclick=" JavaScript: x">x</p>`, `<p onclick=" x">x`}, {`<span Selected="selected"></span>`, `<span selected></span>`}, {`<table><thead><tr><th>foo</th><th>bar</th></tr></thead><tfoot><tr><th>baz</th><th>qux</th></tr></tfoot><tbody><tr><td>boo</td><td>moo</td></tr></tbody></table>`, `<table><thead><tr><th>foo<th>bar<tfoot><tr><th>baz<th>qux<tbody><tr><td>boo<td>moo</table>`}, {`<select><option>foo</option><option>bar</option></select>`, `<select><option>foo<option>bar</select>`}, {`<meta name="keywords" content="A, B">`, `<meta name=keywords content=A,B>`}, {`<script type="text/html"><![CDATA[ <img id="x"> ]]></script>`, `<script type=text/html><img id=x></script>`}, {`<iframe><html> <p> x </p> </html></iframe>`, `<iframe><p>x</iframe>`}, {`<math> ∫_a_^b^{f(x)<over>1+x} dx </math>`, `<math> ∫_a_^b^{f(x)<over>1+x} dx </math>`}, {`<script language="x" charset="x" src="y"></script>`, `<script src=y></script>`}, {`<style media="all">x</style>`, `<style>x</style>`}, {`<a id="abc" name="abc">y</a>`, `<a id=abc>y</a>`}, {`<a id="" value="">y</a>`, `<a value>y</a>`}, // from Kangax html-minfier {`<span style="font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif">text</span>`, `<span style='font-family:"Helvetica Neue","Helvetica",Helvetica,Arial,sans-serif'>text</span>`}, // go-fuzz {`<meta e t n content=ful><a b`, `<meta e t n content=ful><a b>`}, {`<img alt=a'b="">`, `<img alt='a'b=""'>`}, {`</b`, `</b`}, } m := minify.New() m.AddFunc("text/html", Minify) m.AddFunc("text/css", func(_ *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { _, err := io.Copy(w, r) return err }) m.AddFunc("text/javascript", func(_ *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { _, err := io.Copy(w, r) return err }) for _, tt := range htmlTests { r := bytes.NewBufferString(tt.html) w := &bytes.Buffer{} test.Minify(t, tt.html, Minify(m, w, r, nil), w.String(), tt.expected) } }
func TestCSSInline(t *testing.T) { cssTests := []struct { css string expected string }{ {"/*comment*/", ""}, {"/*! bang comment */", ""}, {";", ""}, {"empty:", "empty:"}, {"key: value;", "key:value"}, {"margin: 0 1; padding: 0 1;", "margin:0 1;padding:0 1"}, {"color: #FF0000;", "color:red"}, {"color: #000000;", "color:#000"}, {"color: black;", "color:#000"}, {"color: rgb(255,255,255);", "color:#fff"}, {"color: rgb(100%,100%,100%);", "color:#fff"}, {"color: rgba(255,0,0,1);", "color:red"}, {"color: rgba(255,0,0,2);", "color:red"}, {"color: rgba(255,0,0,0.5);", "color:rgba(255,0,0,.5)"}, {"color: rgba(255,0,0,-1);", "color:transparent"}, {"color: hsl(0,100%,50%);", "color:red"}, {"color: hsla(1,2%,3%,1);", "color:#080807"}, {"color: hsla(1,2%,3%,0);", "color:transparent"}, {"color: hsl(48,100%,50%);", "color:#fc0"}, {"font-weight: bold; font-weight: normal;", "font-weight:700;font-weight:400"}, {"font: bold \"Times new Roman\",\"Sans-Serif\";", "font:700 times new roman,\"sans-serif\""}, {"outline: none;", "outline:0"}, {"outline: none !important;", "outline:0!important"}, {"border-left: none;", "border-left:0"}, {"margin: 1 1 1 1;", "margin:1"}, {"margin: 1 2 1 2;", "margin:1 2"}, {"margin: 1 2 3 2;", "margin:1 2 3"}, {"margin: 1 2 3 4;", "margin:1 2 3 4"}, {"margin: 1 1 1 a;", "margin:1 1 1 a"}, {"margin: 1 1 1 1 !important;", "margin:1!important"}, {"padding:.2em .4em .2em", "padding:.2em .4em"}, {"margin: 0em;", "margin:0"}, {"font-family:'Arial', 'Times New Roman';", "font-family:arial,times new roman"}, {"background:url('http://domain.com/image.png');", "background:url(http://domain.com/image.png)"}, {"filter: progid : DXImageTransform.Microsoft.BasicImage(rotation=1);", "filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"}, {"filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);", "filter:alpha(opacity=0)"}, {"content: \"a\\\nb\";", "content:\"ab\""}, {"content: \"a\\\r\nb\\\r\nc\";", "content:\"abc\""}, {"content: \"\";", "content:\"\""}, {"font:27px/13px arial,sans-serif", "font:27px/13px arial,sans-serif"}, {"text-decoration: none !important", "text-decoration:none!important"}, {"color:#fff", "color:#fff"}, {"border:2px rgb(255,255,255);", "border:2px #fff"}, {"margin:-1px", "margin:-1px"}, {"margin:+1px", "margin:1px"}, {"margin:0.5em", "margin:.5em"}, {"margin:-0.5em", "margin:-.5em"}, {"margin:05em", "margin:5em"}, {"margin:.50em", "margin:.5em"}, {"margin:5.0em", "margin:5em"}, {"margin:5000em", "margin:5e3em"}, {"color:#c0c0c0", "color:silver"}, {"-ms-filter: \"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)\";", "-ms-filter:\"alpha(opacity=80)\""}, {"filter: progid:DXImageTransform.Microsoft.Alpha(Opacity = 80);", "filter:alpha(opacity=80)"}, {"MARGIN:1EM", "margin:1em"}, {"color:CYAN", "color:cyan"}, {"background:URL(x.PNG);", "background:url(x.PNG)"}, {"background:url(/*nocomment*/)", "background:url(/*nocomment*/)"}, {"background:url(data:,text)", "background:url(data:,text)"}, {"background:url('data:text/xml; version = 2.0,content')", "background:url(data:text/xml;version=2.0,content)"}, {"background:url('data:\\'\",text')", "background:url('data:\\'\",text')"}, {"margin:0 0 18px 0;", "margin:0 0 18px"}, {"background:none", "background:0 0"}, {"background:none 1 1", "background:none 1 1"}, {"z-index:1000", "z-index:1000"}, // coverage {"margin: 1 1;", "margin:1"}, {"margin: 1 2;", "margin:1 2"}, {"margin: 1 1 1;", "margin:1"}, {"margin: 1 2 1;", "margin:1 2"}, {"margin: 1 2 3;", "margin:1 2 3"}, {"margin: 0%;", "margin:0"}, {"color: rgb(255,64,64);", "color:#ff4040"}, {"color: rgb(256,-34,2342435);", "color:#f0f"}, {"color: rgb(120%,-45%,234234234%);", "color:#f0f"}, {"color: rgb(0, 1, ident);", "color:rgb(0,1,ident)"}, {"color: rgb(ident);", "color:rgb(ident)"}, {"margin: rgb(ident);", "margin:rgb(ident)"}, {"filter: progid:b().c.Alpha(rgba(x));", "filter:progid:b().c.Alpha(rgba(x))"}, // go-fuzz {"FONT-FAMILY: ru\"", "font-family:ru\""}, } m := minify.New() params := map[string]string{"inline": "1"} for _, tt := range cssTests { r := bytes.NewBufferString(tt.css) w := &bytes.Buffer{} test.Minify(t, tt.css, Minify(m, w, r, params), w.String(), tt.expected) } }
func TestNumber(t *testing.T) { numberTests := []struct { number string expected string }{ {"0", "0"}, {".0", "0"}, {"1.0", "1"}, {"0.1", ".1"}, {"+1", "1"}, {"-1", "-1"}, {"-0.1", "-.1"}, {"10", "10"}, {"100", "100"}, {"1000", "1e3"}, {"0.001", ".001"}, {"0.0001", "1e-4"}, {"100e1", "1e3"}, {"1.1e+1", "11"}, {"1.1e6", "11e5"}, {"0.252", ".252"}, {"1.252", "1.252"}, {"-1.252", "-1.252"}, {"0.075", ".075"}, {"789012345678901234567890123456789e9234567890123456789", "789012345678901234567890123456789e9234567890123456789"}, {".000100009", "100009e-9"}, {".0001000009", ".0001000009"}, {".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009", ".0001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009"}, {"E\x1f", "E\x1f"}, // fuzz {"1e9223372036854775807", "1e9223372036854775807"}, {"11e9223372036854775807", "11e9223372036854775807"}, {".01e-9223372036854775808", ".01e-9223372036854775808"}, {".011e-9223372036854775808", ".011e-9223372036854775808"}, {".12345e8", "12345e3"}, {".12345e7", "1234500"}, {".12345e6", "123450"}, {".12345e5", "12345"}, {".012345e6", "12345"}, {".12345e4", "1234.5"}, {"-.12345e4", "-1234.5"}, {".12345e0", ".12345"}, {".12345e-1", ".012345"}, {".12345e-2", ".0012345"}, {".12345e-3", "12345e-8"}, {".12345e-4", "12345e-9"}, {".12345e-5", "12345e-10"}, {".123456e-3", "123456e-9"}, {".123456e-2", ".00123456"}, {".1234567e-4", "1234567e-11"}, {".1234567e-3", ".0001234567"}, {"12345678e-1", "1234567.8"}, {"72.e-3", ".072"}, {"7640e-2", "76.4"}, {"10.e-3", ".01"}, {".0319e3", "31.9"}, {"39.7e-2", ".397"}, {"39.7e-3", ".0397"}, {".01e1", ".1"}, {".001e1", ".01"}, {"39.7e-5", "397e-6"}, } for _, tt := range numberTests { test.Minify(t, tt.number, nil, string(Number([]byte(tt.number), -1)), tt.expected) } }