|
8 | 8 | package template
|
9 | 9 |
|
10 | 10 | import (
|
| 11 | + "errors" |
11 | 12 | "math"
|
12 | 13 | "strings"
|
13 | 14 | "testing"
|
@@ -106,61 +107,72 @@ func TestNextJsCtx(t *testing.T) {
|
106 | 107 | }
|
107 | 108 | }
|
108 | 109 |
|
| 110 | +type jsonErrType struct{} |
| 111 | + |
| 112 | +func (e *jsonErrType) MarshalJSON() ([]byte, error) { |
| 113 | + return nil, errors.New("beep */ boop </script blip <!--") |
| 114 | +} |
| 115 | + |
109 | 116 | func TestJSValEscaper(t *testing.T) {
|
110 | 117 | tests := []struct {
|
111 |
| - x any |
112 |
| - js string |
| 118 | + x any |
| 119 | + js string |
| 120 | + skipNest bool |
113 | 121 | }{
|
114 |
| - {int(42), " 42 "}, |
115 |
| - {uint(42), " 42 "}, |
116 |
| - {int16(42), " 42 "}, |
117 |
| - {uint16(42), " 42 "}, |
118 |
| - {int32(-42), " -42 "}, |
119 |
| - {uint32(42), " 42 "}, |
120 |
| - {int16(-42), " -42 "}, |
121 |
| - {uint16(42), " 42 "}, |
122 |
| - {int64(-42), " -42 "}, |
123 |
| - {uint64(42), " 42 "}, |
124 |
| - {uint64(1) << 53, " 9007199254740992 "}, |
| 122 | + {int(42), " 42 ", false}, |
| 123 | + {uint(42), " 42 ", false}, |
| 124 | + {int16(42), " 42 ", false}, |
| 125 | + {uint16(42), " 42 ", false}, |
| 126 | + {int32(-42), " -42 ", false}, |
| 127 | + {uint32(42), " 42 ", false}, |
| 128 | + {int16(-42), " -42 ", false}, |
| 129 | + {uint16(42), " 42 ", false}, |
| 130 | + {int64(-42), " -42 ", false}, |
| 131 | + {uint64(42), " 42 ", false}, |
| 132 | + {uint64(1) << 53, " 9007199254740992 ", false}, |
125 | 133 | // ulp(1 << 53) > 1 so this loses precision in JS
|
126 | 134 | // but it is still a representable integer literal.
|
127 |
| - {uint64(1)<<53 + 1, " 9007199254740993 "}, |
128 |
| - {float32(1.0), " 1 "}, |
129 |
| - {float32(-1.0), " -1 "}, |
130 |
| - {float32(0.5), " 0.5 "}, |
131 |
| - {float32(-0.5), " -0.5 "}, |
132 |
| - {float32(1.0) / float32(256), " 0.00390625 "}, |
133 |
| - {float32(0), " 0 "}, |
134 |
| - {math.Copysign(0, -1), " -0 "}, |
135 |
| - {float64(1.0), " 1 "}, |
136 |
| - {float64(-1.0), " -1 "}, |
137 |
| - {float64(0.5), " 0.5 "}, |
138 |
| - {float64(-0.5), " -0.5 "}, |
139 |
| - {float64(0), " 0 "}, |
140 |
| - {math.Copysign(0, -1), " -0 "}, |
141 |
| - {"", `""`}, |
142 |
| - {"foo", `"foo"`}, |
| 135 | + {uint64(1)<<53 + 1, " 9007199254740993 ", false}, |
| 136 | + {float32(1.0), " 1 ", false}, |
| 137 | + {float32(-1.0), " -1 ", false}, |
| 138 | + {float32(0.5), " 0.5 ", false}, |
| 139 | + {float32(-0.5), " -0.5 ", false}, |
| 140 | + {float32(1.0) / float32(256), " 0.00390625 ", false}, |
| 141 | + {float32(0), " 0 ", false}, |
| 142 | + {math.Copysign(0, -1), " -0 ", false}, |
| 143 | + {float64(1.0), " 1 ", false}, |
| 144 | + {float64(-1.0), " -1 ", false}, |
| 145 | + {float64(0.5), " 0.5 ", false}, |
| 146 | + {float64(-0.5), " -0.5 ", false}, |
| 147 | + {float64(0), " 0 ", false}, |
| 148 | + {math.Copysign(0, -1), " -0 ", false}, |
| 149 | + {"", `""`, false}, |
| 150 | + {"foo", `"foo"`, false}, |
143 | 151 | // Newlines.
|
144 |
| - {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`}, |
| 152 | + {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false}, |
145 | 153 | // "\v" == "v" on IE 6 so use "\u000b" instead.
|
146 |
| - {"\t\x0b", `"\t\u000b"`}, |
147 |
| - {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`}, |
148 |
| - {[]any{}, "[]"}, |
149 |
| - {[]any{42, "foo", nil}, `[42,"foo",null]`}, |
150 |
| - {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`}, |
151 |
| - {"<!--", `"\u003c!--"`}, |
152 |
| - {"-->", `"--\u003e"`}, |
153 |
| - {"<![CDATA[", `"\u003c![CDATA["`}, |
154 |
| - {"]]>", `"]]\u003e"`}, |
155 |
| - {"</script", `"\u003c/script"`}, |
156 |
| - {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E" |
157 |
| - {nil, " null "}, |
| 154 | + {"\t\x0b", `"\t\u000b"`, false}, |
| 155 | + {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false}, |
| 156 | + {[]any{}, "[]", false}, |
| 157 | + {[]any{42, "foo", nil}, `[42,"foo",null]`, false}, |
| 158 | + {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false}, |
| 159 | + {"<!--", `"\u003c!--"`, false}, |
| 160 | + {"-->", `"--\u003e"`, false}, |
| 161 | + {"<![CDATA[", `"\u003c![CDATA["`, false}, |
| 162 | + {"]]>", `"]]\u003e"`, false}, |
| 163 | + {"</script", `"\u003c/script"`, false}, |
| 164 | + {"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E" |
| 165 | + {nil, " null ", false}, |
| 166 | + {&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true}, |
158 | 167 | }
|
159 | 168 |
|
160 | 169 | for _, test := range tests {
|
161 | 170 | if js := jsValEscaper(test.x); js != test.js {
|
162 | 171 | t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
|
163 | 172 | }
|
| 173 | + if test.skipNest { |
| 174 | + continue |
| 175 | + } |
164 | 176 | // Make sure that escaping corner cases are not broken
|
165 | 177 | // by nesting.
|
166 | 178 | a := []any{test.x}
|
|
0 commit comments