...

Source file src/html/template/css_test.go

Documentation: html/template

		 1  // Copyright 2011 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package template
		 6  
		 7  import (
		 8  	"strconv"
		 9  	"strings"
		10  	"testing"
		11  )
		12  
		13  func TestEndsWithCSSKeyword(t *testing.T) {
		14  	tests := []struct {
		15  		css, kw string
		16  		want		bool
		17  	}{
		18  		{"", "url", false},
		19  		{"url", "url", true},
		20  		{"URL", "url", true},
		21  		{"Url", "url", true},
		22  		{"url", "important", false},
		23  		{"important", "important", true},
		24  		{"image-url", "url", false},
		25  		{"imageurl", "url", false},
		26  		{"image url", "url", true},
		27  	}
		28  	for _, test := range tests {
		29  		got := endsWithCSSKeyword([]byte(test.css), test.kw)
		30  		if got != test.want {
		31  			t.Errorf("want %t but got %t for css=%v, kw=%v", test.want, got, test.css, test.kw)
		32  		}
		33  	}
		34  }
		35  
		36  func TestIsCSSNmchar(t *testing.T) {
		37  	tests := []struct {
		38  		rune rune
		39  		want bool
		40  	}{
		41  		{0, false},
		42  		{'0', true},
		43  		{'9', true},
		44  		{'A', true},
		45  		{'Z', true},
		46  		{'a', true},
		47  		{'z', true},
		48  		{'_', true},
		49  		{'-', true},
		50  		{':', false},
		51  		{';', false},
		52  		{' ', false},
		53  		{0x7f, false},
		54  		{0x80, true},
		55  		{0x1234, true},
		56  		{0xd800, false},
		57  		{0xdc00, false},
		58  		{0xfffe, false},
		59  		{0x10000, true},
		60  		{0x110000, false},
		61  	}
		62  	for _, test := range tests {
		63  		got := isCSSNmchar(test.rune)
		64  		if got != test.want {
		65  			t.Errorf("%q: want %t but got %t", string(test.rune), test.want, got)
		66  		}
		67  	}
		68  }
		69  
		70  func TestDecodeCSS(t *testing.T) {
		71  	tests := []struct {
		72  		css, want string
		73  	}{
		74  		{``, ``},
		75  		{`foo`, `foo`},
		76  		{`foo\`, `foo`},
		77  		{`foo\\`, `foo\`},
		78  		{`\`, ``},
		79  		{`\A`, "\n"},
		80  		{`\a`, "\n"},
		81  		{`\0a`, "\n"},
		82  		{`\00000a`, "\n"},
		83  		{`\000000a`, "\u0000a"},
		84  		{`\1234 5`, "\u1234" + "5"},
		85  		{`\1234\20 5`, "\u1234" + " 5"},
		86  		{`\1234\A 5`, "\u1234" + "\n5"},
		87  		{"\\1234\t5", "\u1234" + "5"},
		88  		{"\\1234\n5", "\u1234" + "5"},
		89  		{"\\1234\r\n5", "\u1234" + "5"},
		90  		{`\12345`, "\U00012345"},
		91  		{`\\`, `\`},
		92  		{`\\ `, `\ `},
		93  		{`\"`, `"`},
		94  		{`\'`, `'`},
		95  		{`\.`, `.`},
		96  		{`\. .`, `. .`},
		97  		{
		98  			`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e	fox jumps\2028over the \3c canine class=\22lazy\22 \3e dog\3c/canine\3e`,
		99  			"The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>",
	 100  		},
	 101  	}
	 102  	for _, test := range tests {
	 103  		got1 := string(decodeCSS([]byte(test.css)))
	 104  		if got1 != test.want {
	 105  			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.css, test.want, got1)
	 106  		}
	 107  		recoded := cssEscaper(got1)
	 108  		if got2 := string(decodeCSS([]byte(recoded))); got2 != test.want {
	 109  			t.Errorf("%q: escape & decode not dual for %q", test.css, recoded)
	 110  		}
	 111  	}
	 112  }
	 113  
	 114  func TestHexDecode(t *testing.T) {
	 115  	for i := 0; i < 0x200000; i += 101 /* coprime with 16 */ {
	 116  		s := strconv.FormatInt(int64(i), 16)
	 117  		if got := int(hexDecode([]byte(s))); got != i {
	 118  			t.Errorf("%s: want %d but got %d", s, i, got)
	 119  		}
	 120  		s = strings.ToUpper(s)
	 121  		if got := int(hexDecode([]byte(s))); got != i {
	 122  			t.Errorf("%s: want %d but got %d", s, i, got)
	 123  		}
	 124  	}
	 125  }
	 126  
	 127  func TestSkipCSSSpace(t *testing.T) {
	 128  	tests := []struct {
	 129  		css, want string
	 130  	}{
	 131  		{"", ""},
	 132  		{"foo", "foo"},
	 133  		{"\n", ""},
	 134  		{"\r\n", ""},
	 135  		{"\r", ""},
	 136  		{"\t", ""},
	 137  		{" ", ""},
	 138  		{"\f", ""},
	 139  		{" foo", "foo"},
	 140  		{"	foo", " foo"},
	 141  		{`\20`, `\20`},
	 142  	}
	 143  	for _, test := range tests {
	 144  		got := string(skipCSSSpace([]byte(test.css)))
	 145  		if got != test.want {
	 146  			t.Errorf("%q: want %q but got %q", test.css, test.want, got)
	 147  		}
	 148  	}
	 149  }
	 150  
	 151  func TestCSSEscaper(t *testing.T) {
	 152  	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
	 153  		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
	 154  		` !"#$%&'()*+,-./` +
	 155  		`0123456789:;<=>?` +
	 156  		`@ABCDEFGHIJKLMNO` +
	 157  		`PQRSTUVWXYZ[\]^_` +
	 158  		"`abcdefghijklmno" +
	 159  		"pqrstuvwxyz{|}~\x7f" +
	 160  		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
	 161  
	 162  	want := ("\\0\x01\x02\x03\x04\x05\x06\x07" +
	 163  		"\x08\\9 \\a\x0b\\c \\d\x0E\x0F" +
	 164  		"\x10\x11\x12\x13\x14\x15\x16\x17" +
	 165  		"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
	 166  		` !\22#$%\26\27\28\29*\2b,-.\2f ` +
	 167  		`0123456789\3a\3b\3c=\3e?` +
	 168  		`@ABCDEFGHIJKLMNO` +
	 169  		`PQRSTUVWXYZ[\\]^_` +
	 170  		"`abcdefghijklmno" +
	 171  		`pqrstuvwxyz\7b|\7d~` + "\u007f" +
	 172  		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
	 173  
	 174  	got := cssEscaper(input)
	 175  	if got != want {
	 176  		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
	 177  	}
	 178  
	 179  	got = string(decodeCSS([]byte(got)))
	 180  	if input != got {
	 181  		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", input, got)
	 182  	}
	 183  }
	 184  
	 185  func TestCSSValueFilter(t *testing.T) {
	 186  	tests := []struct {
	 187  		css, want string
	 188  	}{
	 189  		{"", ""},
	 190  		{"foo", "foo"},
	 191  		{"0", "0"},
	 192  		{"0px", "0px"},
	 193  		{"-5px", "-5px"},
	 194  		{"1.25in", "1.25in"},
	 195  		{"+.33em", "+.33em"},
	 196  		{"100%", "100%"},
	 197  		{"12.5%", "12.5%"},
	 198  		{".foo", ".foo"},
	 199  		{"#bar", "#bar"},
	 200  		{"corner-radius", "corner-radius"},
	 201  		{"-moz-corner-radius", "-moz-corner-radius"},
	 202  		{"#000", "#000"},
	 203  		{"#48f", "#48f"},
	 204  		{"#123456", "#123456"},
	 205  		{"U+00-FF, U+980-9FF", "U+00-FF, U+980-9FF"},
	 206  		{"color: red", "color: red"},
	 207  		{"<!--", "ZgotmplZ"},
	 208  		{"-->", "ZgotmplZ"},
	 209  		{"<![CDATA[", "ZgotmplZ"},
	 210  		{"]]>", "ZgotmplZ"},
	 211  		{"</style", "ZgotmplZ"},
	 212  		{`"`, "ZgotmplZ"},
	 213  		{`'`, "ZgotmplZ"},
	 214  		{"`", "ZgotmplZ"},
	 215  		{"\x00", "ZgotmplZ"},
	 216  		{"/* foo */", "ZgotmplZ"},
	 217  		{"//", "ZgotmplZ"},
	 218  		{"[href=~", "ZgotmplZ"},
	 219  		{"expression(alert(1337))", "ZgotmplZ"},
	 220  		{"-expression(alert(1337))", "ZgotmplZ"},
	 221  		{"expression", "ZgotmplZ"},
	 222  		{"Expression", "ZgotmplZ"},
	 223  		{"EXPRESSION", "ZgotmplZ"},
	 224  		{"-moz-binding", "ZgotmplZ"},
	 225  		{"-expr\x00ession(alert(1337))", "ZgotmplZ"},
	 226  		{`-expr\0ession(alert(1337))`, "ZgotmplZ"},
	 227  		{`-express\69on(alert(1337))`, "ZgotmplZ"},
	 228  		{`-express\69 on(alert(1337))`, "ZgotmplZ"},
	 229  		{`-exp\72 ession(alert(1337))`, "ZgotmplZ"},
	 230  		{`-exp\52 ession(alert(1337))`, "ZgotmplZ"},
	 231  		{`-exp\000052 ession(alert(1337))`, "ZgotmplZ"},
	 232  		{`-expre\0000073sion`, "-expre\x073sion"},
	 233  		{`@import url evil.css`, "ZgotmplZ"},
	 234  	}
	 235  	for _, test := range tests {
	 236  		got := cssValueFilter(test.css)
	 237  		if got != test.want {
	 238  			t.Errorf("%q: want %q but got %q", test.css, test.want, got)
	 239  		}
	 240  	}
	 241  }
	 242  
	 243  func BenchmarkCSSEscaper(b *testing.B) {
	 244  	for i := 0; i < b.N; i++ {
	 245  		cssEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
	 246  	}
	 247  }
	 248  
	 249  func BenchmarkCSSEscaperNoSpecials(b *testing.B) {
	 250  	for i := 0; i < b.N; i++ {
	 251  		cssEscaper("The quick, brown fox jumps over the lazy dog.")
	 252  	}
	 253  }
	 254  
	 255  func BenchmarkDecodeCSS(b *testing.B) {
	 256  	s := []byte(`The \3c i\3equick\3c/i\3e,\d\A\3cspan style=\27 color:brown\27\3e brown\3c/span\3e fox jumps\2028over the \3c canine class=\22lazy\22 \3edog\3c/canine\3e`)
	 257  	b.ResetTimer()
	 258  	for i := 0; i < b.N; i++ {
	 259  		decodeCSS(s)
	 260  	}
	 261  }
	 262  
	 263  func BenchmarkDecodeCSSNoSpecials(b *testing.B) {
	 264  	s := []byte("The quick, brown fox jumps over the lazy dog.")
	 265  	b.ResetTimer()
	 266  	for i := 0; i < b.N; i++ {
	 267  		decodeCSS(s)
	 268  	}
	 269  }
	 270  
	 271  func BenchmarkCSSValueFilter(b *testing.B) {
	 272  	for i := 0; i < b.N; i++ {
	 273  		cssValueFilter(`	e\78preS\0Sio/**/n(alert(1337))`)
	 274  	}
	 275  }
	 276  
	 277  func BenchmarkCSSValueFilterOk(b *testing.B) {
	 278  	for i := 0; i < b.N; i++ {
	 279  		cssValueFilter(`Times New Roman`)
	 280  	}
	 281  }
	 282  

View as plain text