Skip to content

Commit 6e9ba60

Browse files
adding tests for externalize strings
1 parent 2f20d46 commit 6e9ba60

3 files changed

Lines changed: 204 additions & 15 deletions

File tree

compiler/utils_test.go

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package compiler
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/gopherjs/gopherjs/internal/srctesting"
8+
)
9+
10+
func Test_encodeString(t *testing.T) {
11+
tests := []struct {
12+
name string
13+
in string
14+
wantUtf8 string
15+
wantUtf16 string
16+
}{
17+
{
18+
name: `empty`,
19+
in: ``,
20+
wantUtf8: `""`,
21+
wantUtf16: `""`,
22+
},
23+
{
24+
name: `ascii`,
25+
in: `hello`,
26+
wantUtf8: `"hello"`,
27+
wantUtf16: `"hello"`,
28+
},
29+
{
30+
name: `escape backslash`,
31+
in: `a\b`,
32+
wantUtf8: `"a\\b"`,
33+
wantUtf16: `"a\\b"`,
34+
},
35+
{
36+
name: `escape double quote`,
37+
in: `a"b`,
38+
wantUtf8: `"a\"b"`,
39+
wantUtf16: `"a\"b"`,
40+
},
41+
{
42+
name: `escape control runes`,
43+
in: "\b\f\n\r\t\v",
44+
wantUtf8: `"\b\f\n\r\t\v"`,
45+
wantUtf16: `"\b\f\n\r\t\v"`,
46+
},
47+
{
48+
name: `escape low non-printable`,
49+
in: "\x00\x01\x1f",
50+
wantUtf8: `"\x00\x01\x1F"`,
51+
wantUtf16: `"\x00\x01\x1F"`,
52+
},
53+
{
54+
name: `escape DEL (with é for non-ASCII path)`,
55+
in: "\u00e9\x7f",
56+
wantUtf8: `"\xC3\xA9\x7F"`,
57+
wantUtf16: `"\u00E9\u007F"`,
58+
},
59+
{
60+
name: `printable boundary`,
61+
in: " ~",
62+
wantUtf8: `" ~"`,
63+
wantUtf16: `" ~"`,
64+
},
65+
{
66+
name: `UTF-8 BMP bytes (é)`,
67+
in: "h\xc3\xa9llo",
68+
wantUtf8: `"h\xC3\xA9llo"`,
69+
wantUtf16: `"h\u00E9llo"`,
70+
},
71+
{
72+
name: `UTF-8 CJK bytes`,
73+
in: "日本語",
74+
wantUtf8: `"\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"`,
75+
wantUtf16: `"\u65E5\u672C\u8A9E"`,
76+
},
77+
{
78+
name: `UTF-8 supplementary plane bytes and UTF-16 surrogate pair (😀)`,
79+
in: "\U0001F600",
80+
wantUtf8: `"\xF0\x9F\x98\x80"`,
81+
wantUtf16: `"\uD83D\uDE00"`,
82+
},
83+
{
84+
name: `control char in non-ASCII for UTF-16 path stays escaped as \n`,
85+
in: "\u00e9\n",
86+
wantUtf8: `"\xC3\xA9\n"`,
87+
wantUtf16: `"\u00E9\n"`,
88+
},
89+
{
90+
name: `UTF-16 high BMP edge (U+FFFF)`,
91+
in: "\uffff",
92+
wantUtf8: `"\xEF\xBF\xBF"`,
93+
wantUtf16: `"\uFFFF"`,
94+
},
95+
{
96+
name: `UTF-16 low supplementary edge (U+10000)`,
97+
in: "\U00010000",
98+
wantUtf8: `"\xF0\x90\x80\x80"`,
99+
wantUtf16: `"\uD800\uDC00"`,
100+
},
101+
{
102+
name: `UTF-16 high supplementary edge (U+10FFFF)`,
103+
in: "\U0010FFFF",
104+
wantUtf8: `"\xF4\x8F\xBF\xBF"`,
105+
wantUtf16: `"\uDBFF\uDFFF"`,
106+
},
107+
}
108+
for _, tt := range tests {
109+
t.Run(tt.name, func(t *testing.T) {
110+
if got := encodeString(tt.in); got != tt.wantUtf8 {
111+
t.Errorf("UTF-8: encodeString(%q):\n\tgot: %q\n\twant: %q", tt.in, got, tt.wantUtf8)
112+
}
113+
if got := preexternalizeString(tt.in); got != tt.wantUtf16 {
114+
t.Errorf("UTF-16: preexternalizeString(%q):\n\tgot: %q\n\twant: %q", tt.in, got, tt.wantUtf16)
115+
}
116+
})
117+
}
118+
}
119+
120+
func TestExternalize_LiteralVsRuntime(t *testing.T) {
121+
const src = `
122+
package main
123+
124+
import "github.com/gopherjs/gopherjs/js"
125+
126+
func setStuff(obj *js.Object, dyn string) {
127+
obj.Set("ascii", "hello")
128+
obj.Set("unicode", "h` + "\u00e9" + `llo")
129+
obj.Set("emoji", "` + "\U0001F600" + `")
130+
obj.Set("dynamic", dyn)
131+
obj.Set("concat", "pre-" + dyn)
132+
}
133+
134+
func main() {
135+
setStuff(nil, "")
136+
}
137+
`
138+
srcFiles := []srctesting.Source{{Name: `main.go`, Contents: []byte(src)}}
139+
out := compile(t, srcFiles, false)
140+
141+
mustContain := []struct {
142+
name string
143+
good string
144+
bad string
145+
}{
146+
{
147+
name: "ASCII literal pre-externalized as plain JS string",
148+
good: `"hello"`,
149+
},
150+
{
151+
name: "BMP literal pre-externalized as UTF-16 escapes",
152+
good: `"h\u00E9llo"`,
153+
},
154+
{
155+
name: "Supplementary literal pre-externalized as surrogate pair",
156+
good: `"\uD83D\uDE00"`,
157+
},
158+
{
159+
name: "Plain string variable falls back to runtime $externalize",
160+
good: `$externalize(dyn, $String)`,
161+
},
162+
{
163+
name: "Computed (non-constant) string falls back to runtime $externalize",
164+
good: `$externalize("pre-" + dyn, $String)`,
165+
},
166+
{
167+
name: "ASCII literal must not be wrapped in $externalize",
168+
bad: `$externalize("hello"`,
169+
},
170+
{
171+
name: "BMP literal must not be wrapped in $externalize",
172+
bad: `$externalize("h\u00E9llo"`,
173+
},
174+
{
175+
name: "Supplementary literal must not be wrapped in $externalize",
176+
bad: `$externalize("\uD83D\uDE00"`,
177+
},
178+
}
179+
for _, c := range mustContain {
180+
t.Run(c.name, func(t *testing.T) {
181+
if len(c.good) > 0 && !strings.Contains(out, c.good) {
182+
t.Errorf("compiled output missing %q\n--- output ---\n%s", c.good, out)
183+
}
184+
if len(c.bad) > 0 && strings.Contains(out, c.bad) {
185+
t.Errorf("compiled output unexpectedly contains %q\n--- output ---\n%s", c.bad, out)
186+
}
187+
})
188+
}
189+
}

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ go 1.21
55
require (
66
github.com/evanw/esbuild v0.25.4
77
github.com/fsnotify/fsnotify v1.5.1
8-
github.com/google/go-cmp v0.5.8
8+
github.com/google/go-cmp v0.6.0
99
github.com/msvitok77/goembed v0.3.5
1010
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86
1111
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c
1212
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636
1313
github.com/sirupsen/logrus v1.8.3
1414
github.com/spf13/cobra v1.9.1
1515
github.com/spf13/pflag v1.0.6
16-
golang.org/x/sync v0.5.0
17-
golang.org/x/sys v0.10.0
16+
golang.org/x/sync v0.8.0
17+
golang.org/x/sys v0.23.0
1818
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171
19-
golang.org/x/tools v0.16.0
19+
golang.org/x/tools v0.24.0
2020
)
2121

2222
require (
2323
github.com/inconshreveable/mousetrap v1.1.0 // indirect
24-
golang.org/x/mod v0.14.0 // indirect
24+
golang.org/x/mod v0.20.0 // indirect
2525
)

go.sum

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ github.com/evanw/esbuild v0.25.4 h1:k1bTSim+usBG27w7BfOCorhgx3tO+6bAfMj5pR+6SKg=
66
github.com/evanw/esbuild v0.25.4/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
77
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
88
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
9-
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
10-
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
9+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
1111
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
1212
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
1313
github.com/msvitok77/goembed v0.3.5 h1:SNdkLLipv4YGNVWCVCn+/N01aSp7Ga6/YOcB+kYxnhk=
@@ -30,18 +30,18 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
3030
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3131
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
3232
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
33-
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
34-
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
35-
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
36-
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
33+
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
34+
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
35+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
36+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
3737
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3838
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39-
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
40-
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39+
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
40+
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
4141
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8=
4242
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
43-
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
44-
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
43+
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
44+
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
4545
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
4646
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
4747
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)