1 package goja
2
3 import (
4 "reflect"
5 "testing"
6 )
7
8 func TestGoSliceReflectBasic(t *testing.T) {
9 const SCRIPT = `
10 var sum = 0;
11 for (var i = 0; i < a.length; i++) {
12 sum += a[i];
13 }
14 sum;
15 `
16 r := New()
17 r.Set("a", []int{1, 2, 3, 4})
18 v, err := r.RunString(SCRIPT)
19 if err != nil {
20 t.Fatal(err)
21 }
22 if i := v.ToInteger(); i != 10 {
23 t.Fatalf("Expected 10, got: %d", i)
24 }
25
26 }
27
28 func TestGoSliceReflectIn(t *testing.T) {
29 const SCRIPT = `
30 var idx = "";
31 for (var i in a) {
32 idx += i;
33 }
34 idx;
35 `
36 r := New()
37 r.Set("a", []int{1, 2, 3, 4})
38 v, err := r.RunString(SCRIPT)
39 if err != nil {
40 t.Fatal(err)
41 }
42 if i := v.String(); i != "0123" {
43 t.Fatalf("Expected '0123', got: '%s'", i)
44 }
45 }
46
47 func TestGoSliceReflectSet(t *testing.T) {
48 const SCRIPT = `
49 a[0] = 33;
50 a[1] = 333;
51 a[2] = "42";
52 a[3] = {};
53 a[4] = 0;
54 `
55 r := New()
56 a := []int8{1, 2, 3, 4}
57 r.Set("a", a)
58 _, err := r.RunString(SCRIPT)
59 if err != nil {
60 t.Fatal(err)
61 }
62
63 if a[0] != 33 {
64 t.Fatalf("a[0] = %d, expected 33", a[0])
65 }
66 if a[1] != 77 {
67 t.Fatalf("a[1] = %d, expected 77", a[1])
68 }
69 if a[2] != 42 {
70 t.Fatalf("a[2] = %d, expected 42", a[2])
71 }
72 if a[3] != 0 {
73 t.Fatalf("a[3] = %d, expected 0", a[3])
74 }
75 }
76
77 func TestGoSliceReflectPush(t *testing.T) {
78
79 r := New()
80
81 t.Run("Can push to array by array ptr", func(t *testing.T) {
82 a := []int8{1}
83 r.Set("a", &a)
84 _, err := r.RunString(`a.push (10)`)
85 if err != nil {
86 t.Fatal(err)
87 }
88
89 if a[1] != 10 {
90 t.Fatalf("a[1] = %d, expected 10", a[1])
91 }
92 })
93
94 t.Run("Can push to array by struct ptr", func(t *testing.T) {
95 type testStr struct {
96 A []int
97 }
98 a := testStr{
99 A: []int{2},
100 }
101
102 r.Set("a", &a)
103 _, err := r.RunString(`a.A.push (10)`)
104 if err != nil {
105 t.Fatal(err)
106 }
107
108 if a.A[1] != 10 {
109 t.Fatalf("a[1] = %v, expected 10", a)
110 }
111 })
112
113 }
114
115 func TestGoSliceReflectStructField(t *testing.T) {
116 vm := New()
117 var s struct {
118 A []int
119 B *[]int
120 }
121 vm.Set("s", &s)
122 _, err := vm.RunString(`
123 'use strict';
124 s.A.push(1);
125 if (s.B !== null) {
126 throw new Error("s.B is not null: " + s.B);
127 }
128 s.B = [2];
129 `)
130 if err != nil {
131 t.Fatal(err)
132 }
133 if len(s.A) != 1 || s.A[0] != 1 {
134 t.Fatalf("s.A: %v", s.A)
135 }
136 if len(*s.B) != 1 || (*s.B)[0] != 2 {
137 t.Fatalf("s.B: %v", *s.B)
138 }
139 }
140
141 func TestGoSliceReflectExportToStructField(t *testing.T) {
142 vm := New()
143 v, err := vm.RunString(`({A: [1], B: [2]})`)
144 if err != nil {
145 t.Fatal(err)
146 }
147 var s struct {
148 A []int
149 B *[]int
150 }
151 err = vm.ExportTo(v, &s)
152 if err != nil {
153 t.Fatal(err)
154 }
155 if len(s.A) != 1 || s.A[0] != 1 {
156 t.Fatalf("s.A: %v", s.A)
157 }
158 if len(*s.B) != 1 || (*s.B)[0] != 2 {
159 t.Fatalf("s.B: %v", *s.B)
160 }
161 }
162
163 func TestGoSliceReflectProtoMethod(t *testing.T) {
164 const SCRIPT = `
165 a.join(",")
166 `
167
168 r := New()
169 a := []int8{1, 2, 3, 4}
170 r.Set("a", a)
171 ret, err := r.RunString(SCRIPT)
172 if err != nil {
173 t.Fatal(err)
174 }
175 if s := ret.String(); s != "1,2,3,4" {
176 t.Fatalf("Unexpected result: '%s'", s)
177 }
178 }
179
180 type gosliceReflect_withMethods []interface{}
181
182 func (s gosliceReflect_withMethods) Method() bool {
183 return true
184 }
185
186 func TestGoSliceReflectMethod(t *testing.T) {
187 const SCRIPT = `
188 typeof a === "object" && a[0] === 42 && a.Method() === true;
189 `
190
191 vm := New()
192 a := make(gosliceReflect_withMethods, 1)
193 a[0] = 42
194 vm.Set("a", a)
195 v, err := vm.RunString(SCRIPT)
196 if err != nil {
197 t.Fatal(err)
198 }
199 if !v.StrictEquals(valueTrue) {
200 t.Fatalf("Expected true, got %v", v)
201 }
202
203 }
204
205 func TestGoSliceReflectGetStr(t *testing.T) {
206 r := New()
207 v := r.ToValue([]string{"test"})
208 if o, ok := v.(*Object); ok {
209 if e := o.Get("0").Export(); e != "test" {
210 t.Fatalf("Unexpected o.Get(\"0\"): %v", e)
211 }
212 }
213 }
214
215 func TestGoSliceReflectNilObjectIfaceVal(t *testing.T) {
216 r := New()
217 a := []Value{(*Object)(nil)}
218 r.Set("a", a)
219 ret, err := r.RunString(`
220 ""+a[0];
221 `)
222 if err != nil {
223 t.Fatal(err)
224 }
225 if !asciiString("null").SameAs(ret) {
226 t.Fatalf("ret: %v", ret)
227 }
228 }
229
230 func TestGoSliceReflectSetLength(t *testing.T) {
231 r := New()
232 a := []int{1, 2, 3, 4}
233 b := []testing.TB{&testing.T{}, &testing.T{}, (*testing.T)(nil)}
234 r.Set("a", &a)
235 r.Set("b", &b)
236 _, err := r.RunString(`
237 'use strict';
238 a.length = 3;
239 if (a.length !== 3) {
240 throw new Error("length="+a.length);
241 }
242 if (a[3] !== undefined) {
243 throw new Error("a[3]="+a[3]);
244 }
245 a.length = 5;
246 if (a.length !== 5) {
247 throw new Error("a.length="+a.length);
248 }
249 if (a[3] !== 0) {
250 throw new Error("a[3]="+a[3]);
251 }
252 if (a[4] !== 0) {
253 throw new Error("a[4]="+a[4]);
254 }
255
256 b.length = 3;
257 if (b.length !== 3) {
258 throw new Error("b.length="+b.length);
259 }
260 if (b[3] !== undefined) {
261 throw new Error("b[3]="+b[3]);
262 }
263 b.length = 5;
264 if (b.length !== 5) {
265 throw new Error("length="+b.length);
266 }
267 if (b[3] !== null) {
268 throw new Error("b[3]="+b[3]);
269 }
270 if (b[4] !== null) {
271 throw new Error("b[4]="+b[4]);
272 }
273 if (b[2] !== null) {
274 throw new Error("b[2]="+b[2]);
275 }
276 `)
277 if err != nil {
278 t.Fatal(err)
279 }
280 }
281
282 func TestGoSliceReflectProto(t *testing.T) {
283 r := New()
284 a := []*Object{{}, nil, {}}
285 r.Set("a", &a)
286 r.testScriptWithTestLib(`
287 var proto = [,2,,4];
288 Object.setPrototypeOf(a, proto);
289 assert.sameValue(a[1], null, "a[1]");
290 assert.sameValue(a[3], 4, "a[3]");
291 var desc = Object.getOwnPropertyDescriptor(a, "1");
292 assert.sameValue(desc.value, null, "desc.value");
293 assert(desc.writable, "writable");
294 assert(desc.enumerable, "enumerable");
295 assert(!desc.configurable, "configurable");
296 var v5;
297 Object.defineProperty(proto, "5", {
298 set: function(v) {
299 v5 = v;
300 }
301 });
302 a[5] = "test";
303 assert.sameValue(v5, "test", "v5");
304 `, _undefined, t)
305 }
306
307 func TestGoSliceReflectProtoProto(t *testing.T) {
308 r := New()
309 a := []*Object{{}, nil, {}}
310 proto := []*Object{{}, {}, {}, {}}
311 r.Set("a", &a)
312 r.Set("proto", proto)
313 _, err := r.RunString(`
314 "use strict";
315 var protoproto = {};
316 Object.defineProperty(protoproto, "3", {
317 value: 42
318 });
319 Object.setPrototypeOf(proto, protoproto);
320 Object.setPrototypeOf(a, proto);
321 if (a.hasOwnProperty("3")) {
322 throw new Error("a.hasOwnProperty(\"3\")");
323 }
324 if (a[3] !== null) {
325 throw new Error("a[3]="+a[3]);
326 }
327 a[3] = null;
328 if (a[3] !== null) {
329 throw new Error("a[3]=" + a[3]);
330 }
331 `)
332 if err != nil {
333 t.Fatal(err)
334 }
335
336 }
337
338 func TestGoSliceReflectDelete(t *testing.T) {
339 r := New()
340 a := []*Object{{}, nil, {}}
341 r.Set("a", a)
342 v, err := r.RunString(`
343 delete a[0] && delete a[1] && delete a[3];
344 `)
345 if err != nil {
346 t.Fatal(err)
347 }
348 if v != valueTrue {
349 t.Fatalf("not true: %v", v)
350 }
351 }
352
353 func TestGoSliceReflectPop(t *testing.T) {
354 r := New()
355 a := []string{"1", "", "3"}
356 r.Set("a", &a)
357 v, err := r.RunString(`
358 a.pop()
359 `)
360 if err != nil {
361 t.Fatal(err)
362 }
363 if !v.SameAs(asciiString("3")) {
364 t.Fatal(v)
365 }
366 }
367
368 func TestGoSliceReflectPopNoPtr(t *testing.T) {
369 r := New()
370 a := []string{"1", "", "3"}
371 r.Set("a", a)
372 v, err := r.RunString(`
373 a.pop()
374 `)
375 if err != nil {
376 t.Fatal(err)
377 }
378 if !v.SameAs(asciiString("3")) {
379 t.Fatal(v)
380 }
381 }
382
383 func TestGoSliceReflectLengthProperty(t *testing.T) {
384 vm := New()
385 vm.Set("s", []int{2, 3, 4})
386 _, err := vm.RunString(`
387 if (!s.hasOwnProperty("length")) {
388 throw new Error("hasOwnProperty() returned false");
389 }
390 let desc = Object.getOwnPropertyDescriptor(s, "length");
391 if (desc.value !== 3 || !desc.writable || desc.enumerable || desc.configurable) {
392 throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
393 }
394 `)
395 if err != nil {
396 t.Fatal(err)
397 }
398 }
399
400 type testCustomSliceWithMethods []int
401
402 func (a testCustomSliceWithMethods) Method() bool {
403 return true
404 }
405
406 func TestGoSliceReflectMethods(t *testing.T) {
407 vm := New()
408 vm.Set("s", testCustomSliceWithMethods{1, 2, 3})
409 _, err := vm.RunString(`
410 if (!s.hasOwnProperty("Method")) {
411 throw new Error("hasOwnProperty() returned false");
412 }
413 let desc = Object.getOwnPropertyDescriptor(s, "Method");
414 if (desc.value() !== true || desc.writable || !desc.enumerable || desc.configurable) {
415 throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
416 }
417 `)
418 if err != nil {
419 t.Fatal(err)
420 }
421 }
422
423 func TestGoSliceReflectExportAfterGrow(t *testing.T) {
424 vm := New()
425 vm.Set("a", []int{1})
426 v, err := vm.RunString(`
427 a.push(2);
428 a;
429 `)
430 if err != nil {
431 t.Fatal(err)
432 }
433 exp := v.Export()
434 if a, ok := exp.([]int); ok {
435 if len(a) != 2 || a[0] != 1 || a[1] != 2 {
436 t.Fatal(a)
437 }
438 } else {
439 t.Fatalf("Wrong type: %T", exp)
440 }
441 }
442
443 func TestGoSliceReflectSort(t *testing.T) {
444 vm := New()
445 type Thing struct{ Name string }
446 vm.Set("v", []*Thing{
447 {Name: "log"},
448 {Name: "etc"},
449 {Name: "test"},
450 {Name: "bin"},
451 })
452 ret, err := vm.RunString(`
453 //v.sort((a, b) => a.Name.localeCompare(b.Name)).map((x) => x.Name);
454 const tmp = v[0];
455 v[0] = v[1];
456 v[1] = tmp;
457 v[0].Name + v[1].Name;
458 `)
459 if err != nil {
460 panic(err)
461 }
462 t.Log(ret.Export())
463 }
464
465 func TestGoSliceReflect111(t *testing.T) {
466 vm := New()
467 vm.Set("v", []int32{
468 1, 2,
469 })
470 ret, err := vm.RunString(`
471 //v.sort((a, b) => a.Name.localeCompare(b.Name)).map((x) => x.Name);
472 const tmp = v[0];
473 v[0] = v[1];
474 v[1] = tmp;
475 "" + v[0] + v[1];
476 `)
477 if err != nil {
478 panic(err)
479 }
480 t.Log(ret.Export())
481 a := []int{1, 2}
482 a0 := reflect.ValueOf(a).Index(0)
483 a0.Set(reflect.ValueOf(0))
484 t.Log(a[0])
485 }
486
487 func TestGoSliceReflectExternalLenUpdate(t *testing.T) {
488 data := &[]int{1}
489
490 vm := New()
491 vm.Set("data", data)
492 vm.Set("append", func(a *[]int, v int) {
493 if a != data {
494 panic(vm.NewTypeError("a != data"))
495 }
496 *a = append(*a, v)
497 })
498
499 vm.testScriptWithTestLib(`
500 assert.sameValue(data.length, 1);
501
502 // modify with js
503 data.push(1);
504 assert.sameValue(data.length, 2);
505
506 // modify with go
507 append(data, 2);
508 assert.sameValue(data.length, 3);
509 `, _undefined, t)
510 }
511
512 func BenchmarkGoSliceReflectSet(b *testing.B) {
513 vm := New()
514 a := vm.ToValue([]int{1}).(*Object)
515 b.ResetTimer()
516 v := intToValue(0)
517 for i := 0; i < b.N; i++ {
518 a.Set("0", v)
519 }
520 }
521
View as plain text