1 package goja
2
3 import (
4 "strings"
5 "testing"
6 "unicode/utf16"
7 )
8
9 func TestStringOOBProperties(t *testing.T) {
10 const SCRIPT = `
11 var string = new String("str");
12
13 string[4] = 1;
14 string[4];
15 `
16
17 testScript(SCRIPT, valueInt(1), t)
18 }
19
20 func TestImportedString(t *testing.T) {
21 vm := New()
22
23 testUnaryOp := func(a, expr string, result interface{}, t *testing.T) {
24 v, err := vm.RunString("a => " + expr)
25 if err != nil {
26 t.Fatal(err)
27 }
28 var fn func(a Value) (Value, error)
29 err = vm.ExportTo(v, &fn)
30 if err != nil {
31 t.Fatal(err)
32 }
33 for _, aa := range []Value{newStringValue(a), vm.ToValue(a)} {
34 res, err := fn(aa)
35 if err != nil {
36 t.Fatal(err)
37 }
38 if res.Export() != result {
39 t.Fatalf("%s, a:%v(%T). expected: %v, actual: %v", expr, aa, aa, result, res)
40 }
41 }
42 }
43
44 testBinaryOp := func(a, b, expr string, result interface{}, t *testing.T) {
45 v, err := vm.RunString("(a, b) => " + expr)
46 if err != nil {
47 t.Fatal(err)
48 }
49 var fn func(a, b Value) (Value, error)
50 err = vm.ExportTo(v, &fn)
51 if err != nil {
52 t.Fatal(err)
53 }
54 for _, aa := range []Value{newStringValue(a), vm.ToValue(a)} {
55 for _, bb := range []Value{newStringValue(b), vm.ToValue(b)} {
56 res, err := fn(aa, bb)
57 if err != nil {
58 t.Fatal(err)
59 }
60 if res.Export() != result {
61 t.Fatalf("%s, a:%v(%T), b:%v(%T). expected: %v, actual: %v", expr, aa, aa, bb, bb, result, res)
62 }
63 }
64 }
65 }
66
67 strs := []string{"shortAscii", "longlongAscii1234567890123456789", "short юникод", "long юникод 1234567890 юникод \U0001F600", "юникод", "Ascii", "long", "код"}
68 indexOfResults := [][]int{
69
76 {0, -1, -1, -1, -1, 5, -1, -1},
77 {-1, 0, -1, -1, -1, 8, 0, -1},
78 {-1, -1, 0, -1, 6, -1, -1, 9},
79 {-1, -1, -1, 0, 5, -1, 0, 8},
80 {-1, -1, -1, -1, 0, -1, -1, 3},
81 {-1, -1, -1, -1, -1, 0, -1, -1},
82 {-1, -1, -1, -1, -1, -1, 0, -1},
83 {-1, -1, -1, -1, -1, -1, -1, 0},
84 }
85
86 lastIndexOfResults := [][]int{
87
92 {0, -1, -1, -1, -1, 5, -1, -1},
93 {-1, 0, -1, -1, -1, 8, 4, -1},
94 {-1, -1, 0, -1, 6, -1, -1, 9},
95 {-1, -1, -1, 0, 23, -1, 0, 26},
96 {-1, -1, -1, -1, 0, -1, -1, 3},
97 {-1, -1, -1, -1, -1, 0, -1, -1},
98 {-1, -1, -1, -1, -1, -1, 0, -1},
99 {-1, -1, -1, -1, -1, -1, -1, 0},
100 }
101
102 pad := func(s, p string, n int, start bool) string {
103 if n == 0 {
104 return s
105 }
106 if p == "" {
107 p = " "
108 }
109 var b strings.Builder
110 ss := utf16.Encode([]rune(s))
111 b.Grow(n)
112 n -= len(ss)
113 if !start {
114 b.WriteString(s)
115 }
116 if n > 0 {
117 pp := utf16.Encode([]rune(p))
118 for n > 0 {
119 if n > len(pp) {
120 b.WriteString(p)
121 n -= len(pp)
122 } else {
123 b.WriteString(string(utf16.Decode(pp[:n])))
124 n = 0
125 }
126 }
127 }
128 if start {
129 b.WriteString(s)
130 }
131 return b.String()
132 }
133
134 for i, a := range strs {
135 testUnaryOp(a, "JSON.parse(JSON.stringify(a))", a, t)
136 testUnaryOp(a, "a.length", int64(len(utf16.Encode([]rune(a)))), t)
137 for j, b := range strs {
138 testBinaryOp(a, b, "a === b", a == b, t)
139 testBinaryOp(a, b, "a == b", a == b, t)
140 testBinaryOp(a, b, "a + b", a+b, t)
141 testBinaryOp(a, b, "a > b", strings.Compare(a, b) > 0, t)
142 testBinaryOp(a, b, "`A${a}B${b}C`", "A"+a+"B"+b+"C", t)
143 testBinaryOp(a, b, "a.indexOf(b)", int64(indexOfResults[i][j]), t)
144 testBinaryOp(a, b, "a.lastIndexOf(b)", int64(lastIndexOfResults[i][j]), t)
145 testBinaryOp(a, b, "a.padStart(32, b)", pad(a, b, 32, true), t)
146 testBinaryOp(a, b, "a.padEnd(32, b)", pad(a, b, 32, false), t)
147 testBinaryOp(a, b, "a.replace(b, '')", strings.Replace(a, b, "", 1), t)
148 }
149 }
150 }
151
152 func TestStringFromUTF16(t *testing.T) {
153 s := StringFromUTF16([]uint16{})
154 if s.Length() != 0 || !s.SameAs(asciiString("")) {
155 t.Fatal(s)
156 }
157
158 s = StringFromUTF16([]uint16{0xD800})
159 if s.Length() != 1 || s.CharAt(0) != 0xD800 {
160 t.Fatal(s)
161 }
162
163 s = StringFromUTF16([]uint16{'A', 'B'})
164 if !s.SameAs(asciiString("AB")) {
165 t.Fatal(s)
166 }
167 }
168
169 func TestStringBuilder(t *testing.T) {
170 t.Run("writeUTF8String-switch", func(t *testing.T) {
171 var sb StringBuilder
172 sb.WriteUTF8String("Head")
173 sb.WriteUTF8String("1ábc")
174 if res := sb.String().String(); res != "Head1ábc" {
175 t.Fatal(res)
176 }
177 })
178 }
179
180 func BenchmarkASCIIConcat(b *testing.B) {
181 vm := New()
182
183 b.ResetTimer()
184 b.ReportAllocs()
185 for i := 0; i < b.N; i++ {
186 _, err := vm.RunString(`{let result = "ab";
187 for (let i = 0 ; i < 10;i++) {
188 result += result;
189 }}`)
190 if err != nil {
191 b.Fatalf("Unexpected errors %s", err)
192 }
193 }
194 }
195
View as plain text