PR c++/86342 - -Wdeprecated-copy and system headers.
[official-gcc.git] / libgo / go / html / template / js_test.go
blob7484f60b54dc6fc6cc8aaa20ffedcb33c028569a
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.
5 package template
7 import (
8 "bytes"
9 "math"
10 "strings"
11 "testing"
14 func TestNextJsCtx(t *testing.T) {
15 tests := []struct {
16 jsCtx jsCtx
17 s string
19 // Statement terminators precede regexps.
20 {jsCtxRegexp, ";"},
21 // This is not airtight.
22 // ({ valueOf: function () { return 1 } } / 2)
23 // is valid JavaScript but in practice, devs do not do this.
24 // A block followed by a statement starting with a RegExp is
25 // much more common:
26 // while (x) {...} /foo/.test(x) || panic()
27 {jsCtxRegexp, "}"},
28 // But member, call, grouping, and array expression terminators
29 // precede div ops.
30 {jsCtxDivOp, ")"},
31 {jsCtxDivOp, "]"},
32 // At the start of a primary expression, array, or expression
33 // statement, expect a regexp.
34 {jsCtxRegexp, "("},
35 {jsCtxRegexp, "["},
36 {jsCtxRegexp, "{"},
37 // Assignment operators precede regexps as do all exclusively
38 // prefix and binary operators.
39 {jsCtxRegexp, "="},
40 {jsCtxRegexp, "+="},
41 {jsCtxRegexp, "*="},
42 {jsCtxRegexp, "*"},
43 {jsCtxRegexp, "!"},
44 // Whether the + or - is infix or prefix, it cannot precede a
45 // div op.
46 {jsCtxRegexp, "+"},
47 {jsCtxRegexp, "-"},
48 // An incr/decr op precedes a div operator.
49 // This is not airtight. In (g = ++/h/i) a regexp follows a
50 // pre-increment operator, but in practice devs do not try to
51 // increment or decrement regular expressions.
52 // (g++/h/i) where ++ is a postfix operator on g is much more
53 // common.
54 {jsCtxDivOp, "--"},
55 {jsCtxDivOp, "++"},
56 {jsCtxDivOp, "x--"},
57 // When we have many dashes or pluses, then they are grouped
58 // left to right.
59 {jsCtxRegexp, "x---"}, // A postfix -- then a -.
60 // return followed by a slash returns the regexp literal or the
61 // slash starts a regexp literal in an expression statement that
62 // is dead code.
63 {jsCtxRegexp, "return"},
64 {jsCtxRegexp, "return "},
65 {jsCtxRegexp, "return\t"},
66 {jsCtxRegexp, "return\n"},
67 {jsCtxRegexp, "return\u2028"},
68 // Identifiers can be divided and cannot validly be preceded by
69 // a regular expressions. Semicolon insertion cannot happen
70 // between an identifier and a regular expression on a new line
71 // because the one token lookahead for semicolon insertion has
72 // to conclude that it could be a div binary op and treat it as
73 // such.
74 {jsCtxDivOp, "x"},
75 {jsCtxDivOp, "x "},
76 {jsCtxDivOp, "x\t"},
77 {jsCtxDivOp, "x\n"},
78 {jsCtxDivOp, "x\u2028"},
79 {jsCtxDivOp, "preturn"},
80 // Numbers precede div ops.
81 {jsCtxDivOp, "0"},
82 // Dots that are part of a number are div preceders.
83 {jsCtxDivOp, "0."},
86 for _, test := range tests {
87 if nextJSCtx([]byte(test.s), jsCtxRegexp) != test.jsCtx {
88 t.Errorf("want %s got %q", test.jsCtx, test.s)
90 if nextJSCtx([]byte(test.s), jsCtxDivOp) != test.jsCtx {
91 t.Errorf("want %s got %q", test.jsCtx, test.s)
95 if nextJSCtx([]byte(" "), jsCtxRegexp) != jsCtxRegexp {
96 t.Error("Blank tokens")
99 if nextJSCtx([]byte(" "), jsCtxDivOp) != jsCtxDivOp {
100 t.Error("Blank tokens")
104 func TestJSValEscaper(t *testing.T) {
105 tests := []struct {
106 x interface{}
107 js string
109 {int(42), " 42 "},
110 {uint(42), " 42 "},
111 {int16(42), " 42 "},
112 {uint16(42), " 42 "},
113 {int32(-42), " -42 "},
114 {uint32(42), " 42 "},
115 {int16(-42), " -42 "},
116 {uint16(42), " 42 "},
117 {int64(-42), " -42 "},
118 {uint64(42), " 42 "},
119 {uint64(1) << 53, " 9007199254740992 "},
120 // ulp(1 << 53) > 1 so this loses precision in JS
121 // but it is still a representable integer literal.
122 {uint64(1)<<53 + 1, " 9007199254740993 "},
123 {float32(1.0), " 1 "},
124 {float32(-1.0), " -1 "},
125 {float32(0.5), " 0.5 "},
126 {float32(-0.5), " -0.5 "},
127 {float32(1.0) / float32(256), " 0.00390625 "},
128 {float32(0), " 0 "},
129 {math.Copysign(0, -1), " -0 "},
130 {float64(1.0), " 1 "},
131 {float64(-1.0), " -1 "},
132 {float64(0.5), " 0.5 "},
133 {float64(-0.5), " -0.5 "},
134 {float64(0), " 0 "},
135 {math.Copysign(0, -1), " -0 "},
136 {"", `""`},
137 {"foo", `"foo"`},
138 // Newlines.
139 {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
140 // "\v" == "v" on IE 6 so use "\x0b" instead.
141 {"\t\x0b", `"\t\u000b"`},
142 {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
143 {[]interface{}{}, "[]"},
144 {[]interface{}{42, "foo", nil}, `[42,"foo",null]`},
145 {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
146 {"<!--", `"\u003c!--"`},
147 {"-->", `"--\u003e"`},
148 {"<![CDATA[", `"\u003c![CDATA["`},
149 {"]]>", `"]]\u003e"`},
150 {"</script", `"\u003c/script"`},
151 {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
154 for _, test := range tests {
155 if js := jsValEscaper(test.x); js != test.js {
156 t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
158 // Make sure that escaping corner cases are not broken
159 // by nesting.
160 a := []interface{}{test.x}
161 want := "[" + strings.TrimSpace(test.js) + "]"
162 if js := jsValEscaper(a); js != want {
163 t.Errorf("%+v: want\n\t%q\ngot\n\t%q", a, want, js)
168 func TestJSStrEscaper(t *testing.T) {
169 tests := []struct {
170 x interface{}
171 esc string
173 {"", ``},
174 {"foo", `foo`},
175 {"\u0000", `\0`},
176 {"\t", `\t`},
177 {"\n", `\n`},
178 {"\r", `\r`},
179 {"\u2028", `\u2028`},
180 {"\u2029", `\u2029`},
181 {"\\", `\\`},
182 {"\\n", `\\n`},
183 {"foo\r\nbar", `foo\r\nbar`},
184 // Preserve attribute boundaries.
185 {`"`, `\x22`},
186 {`'`, `\x27`},
187 // Allow embedding in HTML without further escaping.
188 {`&amp;`, `\x26amp;`},
189 // Prevent breaking out of text node and element boundaries.
190 {"</script>", `\x3c\/script\x3e`},
191 {"<![CDATA[", `\x3c![CDATA[`},
192 {"]]>", `]]\x3e`},
193 // http://dev.w3.org/html5/markup/aria/syntax.html#escaping-text-span
194 // "The text in style, script, title, and textarea elements
195 // must not have an escaping text span start that is not
196 // followed by an escaping text span end."
197 // Furthermore, spoofing an escaping text span end could lead
198 // to different interpretation of a </script> sequence otherwise
199 // masked by the escaping text span, and spoofing a start could
200 // allow regular text content to be interpreted as script
201 // allowing script execution via a combination of a JS string
202 // injection followed by an HTML text injection.
203 {"<!--", `\x3c!--`},
204 {"-->", `--\x3e`},
205 // From http://code.google.com/p/doctype/wiki/ArticleUtf7
206 {"+ADw-script+AD4-alert(1)+ADw-/script+AD4-",
207 `\x2bADw-script\x2bAD4-alert(1)\x2bADw-\/script\x2bAD4-`,
209 // Invalid UTF-8 sequence
210 {"foo\xA0bar", "foo\xA0bar"},
211 // Invalid unicode scalar value.
212 {"foo\xed\xa0\x80bar", "foo\xed\xa0\x80bar"},
215 for _, test := range tests {
216 esc := jsStrEscaper(test.x)
217 if esc != test.esc {
218 t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
223 func TestJSRegexpEscaper(t *testing.T) {
224 tests := []struct {
225 x interface{}
226 esc string
228 {"", `(?:)`},
229 {"foo", `foo`},
230 {"\u0000", `\0`},
231 {"\t", `\t`},
232 {"\n", `\n`},
233 {"\r", `\r`},
234 {"\u2028", `\u2028`},
235 {"\u2029", `\u2029`},
236 {"\\", `\\`},
237 {"\\n", `\\n`},
238 {"foo\r\nbar", `foo\r\nbar`},
239 // Preserve attribute boundaries.
240 {`"`, `\x22`},
241 {`'`, `\x27`},
242 // Allow embedding in HTML without further escaping.
243 {`&amp;`, `\x26amp;`},
244 // Prevent breaking out of text node and element boundaries.
245 {"</script>", `\x3c\/script\x3e`},
246 {"<![CDATA[", `\x3c!\[CDATA\[`},
247 {"]]>", `\]\]\x3e`},
248 // Escaping text spans.
249 {"<!--", `\x3c!\-\-`},
250 {"-->", `\-\-\x3e`},
251 {"*", `\*`},
252 {"+", `\x2b`},
253 {"?", `\?`},
254 {"[](){}", `\[\]\(\)\{\}`},
255 {"$foo|x.y", `\$foo\|x\.y`},
256 {"x^y", `x\^y`},
259 for _, test := range tests {
260 esc := jsRegexpEscaper(test.x)
261 if esc != test.esc {
262 t.Errorf("%q: want %q got %q", test.x, test.esc, esc)
267 func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
268 input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
269 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
270 ` !"#$%&'()*+,-./` +
271 `0123456789:;<=>?` +
272 `@ABCDEFGHIJKLMNO` +
273 `PQRSTUVWXYZ[\]^_` +
274 "`abcdefghijklmno" +
275 "pqrstuvwxyz{|}~\x7f" +
276 "\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
278 tests := []struct {
279 name string
280 escaper func(...interface{}) string
281 escaped string
284 "jsStrEscaper",
285 jsStrEscaper,
286 "\\0\x01\x02\x03\x04\x05\x06\x07" +
287 "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
288 "\x10\x11\x12\x13\x14\x15\x16\x17" +
289 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
290 ` !\x22#$%\x26\x27()*\x2b,-.\/` +
291 `0123456789:;\x3c=\x3e?` +
292 `@ABCDEFGHIJKLMNO` +
293 `PQRSTUVWXYZ[\\]^_` +
294 "`abcdefghijklmno" +
295 "pqrstuvwxyz{|}~\x7f" +
296 "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
299 "jsRegexpEscaper",
300 jsRegexpEscaper,
301 "\\0\x01\x02\x03\x04\x05\x06\x07" +
302 "\x08\\t\\n\\x0b\\f\\r\x0E\x0F" +
303 "\x10\x11\x12\x13\x14\x15\x16\x17" +
304 "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
305 ` !\x22#\$%\x26\x27\(\)\*\x2b,\-\.\/` +
306 `0123456789:;\x3c=\x3e\?` +
307 `@ABCDEFGHIJKLMNO` +
308 `PQRSTUVWXYZ\[\\\]\^_` +
309 "`abcdefghijklmno" +
310 `pqrstuvwxyz\{\|\}~` + "\u007f" +
311 "\u00A0\u0100\\u2028\\u2029\ufeff\U0001D11E",
315 for _, test := range tests {
316 if s := test.escaper(input); s != test.escaped {
317 t.Errorf("%s once: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
318 continue
321 // Escape it rune by rune to make sure that any
322 // fast-path checking does not break escaping.
323 var buf bytes.Buffer
324 for _, c := range input {
325 buf.WriteString(test.escaper(string(c)))
328 if s := buf.String(); s != test.escaped {
329 t.Errorf("%s rune-wise: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
330 continue
335 func TestIsJsMimeType(t *testing.T) {
336 tests := []struct {
337 in string
338 out bool
340 {"application/javascript;version=1.8", true},
341 {"application/javascript;version=1.8;foo=bar", true},
342 {"application/javascript/version=1.8", false},
343 {"text/javascript", true},
344 {"application/json", true},
347 for _, test := range tests {
348 if isJSType(test.in) != test.out {
349 t.Errorf("isJSType(%q) = %v, want %v", test.in, !test.out, test.out)
354 func BenchmarkJSValEscaperWithNum(b *testing.B) {
355 for i := 0; i < b.N; i++ {
356 jsValEscaper(3.141592654)
360 func BenchmarkJSValEscaperWithStr(b *testing.B) {
361 for i := 0; i < b.N; i++ {
362 jsValEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
366 func BenchmarkJSValEscaperWithStrNoSpecials(b *testing.B) {
367 for i := 0; i < b.N; i++ {
368 jsValEscaper("The quick, brown fox jumps over the lazy dog")
372 func BenchmarkJSValEscaperWithObj(b *testing.B) {
373 o := struct {
374 S string
375 N int
377 "The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>\u2028",
380 for i := 0; i < b.N; i++ {
381 jsValEscaper(o)
385 func BenchmarkJSValEscaperWithObjNoSpecials(b *testing.B) {
386 o := struct {
387 S string
388 N int
390 "The quick, brown fox jumps over the lazy dog",
393 for i := 0; i < b.N; i++ {
394 jsValEscaper(o)
398 func BenchmarkJSStrEscaperNoSpecials(b *testing.B) {
399 for i := 0; i < b.N; i++ {
400 jsStrEscaper("The quick, brown fox jumps over the lazy dog.")
404 func BenchmarkJSStrEscaper(b *testing.B) {
405 for i := 0; i < b.N; i++ {
406 jsStrEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")
410 func BenchmarkJSRegexpEscaperNoSpecials(b *testing.B) {
411 for i := 0; i < b.N; i++ {
412 jsRegexpEscaper("The quick, brown fox jumps over the lazy dog")
416 func BenchmarkJSRegexpEscaper(b *testing.B) {
417 for i := 0; i < b.N; i++ {
418 jsRegexpEscaper("The <i>quick</i>,\r\n<span style='color:brown'>brown</span> fox jumps\u2028over the <canine class=\"lazy\">dog</canine>")