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