1 package goja
2
3 import (
4 "errors"
5 "fmt"
6 "math"
7 "reflect"
8 "strings"
9 "testing"
10 "time"
11 )
12
13 func TestGoReflectGet(t *testing.T) {
14 const SCRIPT = `
15 o.X + o.Y;
16 `
17 type O struct {
18 X int
19 Y string
20 }
21 r := New()
22 o := O{X: 4, Y: "2"}
23 r.Set("o", o)
24
25 v, err := r.RunString(SCRIPT)
26 if err != nil {
27 t.Fatal(err)
28 }
29
30 if s, ok := v.(String); ok {
31 if s.String() != "42" {
32 t.Fatalf("Unexpected string: %s", s)
33 }
34 } else {
35 t.Fatalf("Unexpected type: %s", v)
36 }
37 }
38
39 func TestGoReflectSet(t *testing.T) {
40 const SCRIPT = `
41 o.X++;
42 o.Y += "P";
43 `
44 type O struct {
45 X int
46 Y string
47 }
48 r := New()
49 o := O{X: 4, Y: "2"}
50 r.Set("o", &o)
51
52 _, err := r.RunString(SCRIPT)
53 if err != nil {
54 t.Fatal(err)
55 }
56
57 if o.X != 5 {
58 t.Fatalf("Unexpected X: %d", o.X)
59 }
60
61 if o.Y != "2P" {
62 t.Fatalf("Unexpected Y: %s", o.Y)
63 }
64
65 r.Set("o", o)
66 _, err = r.RunString(SCRIPT)
67 if err != nil {
68 t.Fatal(err)
69 }
70
71 if res, ok := r.Get("o").Export().(O); ok {
72 if res.X != 6 {
73 t.Fatalf("Unexpected res.X: %d", res.X)
74 }
75
76 if res.Y != "2PP" {
77 t.Fatalf("Unexpected res.Y: %s", res.Y)
78 }
79 }
80 }
81
82 func TestGoReflectEnumerate(t *testing.T) {
83 const SCRIPT = `
84 var hasX = false;
85 var hasY = false;
86 for (var key in o) {
87 switch (key) {
88 case "X":
89 if (hasX) {
90 throw "Already have X";
91 }
92 hasX = true;
93 break;
94 case "Y":
95 if (hasY) {
96 throw "Already have Y";
97 }
98 hasY = true;
99 break;
100 default:
101 throw "Unexpected property: " + key;
102 }
103 }
104 hasX && hasY;
105 `
106
107 type S struct {
108 X, Y int
109 }
110
111 r := New()
112 r.Set("o", S{X: 40, Y: 2})
113 v, err := r.RunString(SCRIPT)
114 if err != nil {
115 t.Fatal(err)
116 }
117
118 if !v.StrictEquals(valueTrue) {
119 t.Fatalf("Expected true, got %v", v)
120 }
121
122 }
123
124 func TestGoReflectCustomIntUnbox(t *testing.T) {
125 const SCRIPT = `
126 i + 2;
127 `
128
129 type CustomInt int
130 var i CustomInt = 40
131
132 r := New()
133 r.Set("i", i)
134 v, err := r.RunString(SCRIPT)
135 if err != nil {
136 t.Fatal(err)
137 }
138
139 if !v.StrictEquals(intToValue(42)) {
140 t.Fatalf("Expected int 42, got %v", v)
141 }
142 }
143
144 func TestGoReflectPreserveCustomType(t *testing.T) {
145 const SCRIPT = `
146 i;
147 `
148
149 type CustomInt int
150 var i CustomInt = 42
151
152 r := New()
153 r.Set("i", i)
154 v, err := r.RunString(SCRIPT)
155 if err != nil {
156 t.Fatal(err)
157 }
158
159 ve := v.Export()
160
161 if ii, ok := ve.(CustomInt); ok {
162 if ii != i {
163 t.Fatalf("Wrong value: %v", ii)
164 }
165 } else {
166 t.Fatalf("Wrong type: %v", ve)
167 }
168 }
169
170 func TestGoReflectCustomIntValueOf(t *testing.T) {
171 const SCRIPT = `
172 if (i instanceof Number) {
173 i.valueOf();
174 } else {
175 throw new Error("Value is not a number");
176 }
177 `
178
179 type CustomInt int
180 var i CustomInt = 42
181
182 r := New()
183 r.Set("i", i)
184 v, err := r.RunString(SCRIPT)
185 if err != nil {
186 t.Fatal(err)
187 }
188
189 if !v.StrictEquals(intToValue(42)) {
190 t.Fatalf("Expected int 42, got %v", v)
191 }
192 }
193
194 func TestGoReflectEqual(t *testing.T) {
195 const SCRIPT = `
196 x === y;
197 `
198
199 type CustomInt int
200 var x CustomInt = 42
201 var y CustomInt = 42
202
203 r := New()
204 r.Set("x", x)
205 r.Set("y", y)
206 v, err := r.RunString(SCRIPT)
207 if err != nil {
208 t.Fatal(err)
209 }
210
211 if !v.StrictEquals(valueTrue) {
212 t.Fatalf("Expected true, got %v", v)
213 }
214 }
215
216 type testGoReflectMethod_O struct {
217 field string
218 Test string
219 }
220
221 func (o testGoReflectMethod_O) Method(s string) string {
222 return o.field + s
223 }
224
225 func TestGoReflectMethod(t *testing.T) {
226 const SCRIPT = `
227 o.Method(" 123")
228 `
229
230 o := testGoReflectMethod_O{
231 field: "test",
232 }
233
234 r := New()
235 r.Set("o", &o)
236 v, err := r.RunString(SCRIPT)
237 if err != nil {
238 t.Fatal(err)
239 }
240
241 if !v.StrictEquals(asciiString("test 123")) {
242 t.Fatalf("Expected 'test 123', got %v", v)
243 }
244 }
245
246 func (o *testGoReflectMethod_O) Set(s string) {
247 o.field = s
248 }
249
250 func (o *testGoReflectMethod_O) Get() string {
251 return o.field
252 }
253
254 func TestGoReflectMethodPtr(t *testing.T) {
255 const SCRIPT = `
256 o.Set("42")
257 o.Get()
258 `
259
260 o := testGoReflectMethod_O{
261 field: "test",
262 }
263
264 r := New()
265 r.Set("o", &o)
266 v, err := r.RunString(SCRIPT)
267 if err != nil {
268 t.Fatal(err)
269 }
270
271 if !v.StrictEquals(asciiString("42")) {
272 t.Fatalf("Expected '42', got %v", v)
273 }
274 }
275
276 func (b *testBoolS) Method() bool {
277 return bool(*b)
278 }
279
280 func TestGoReflectPtrMethodOnNonPtrValue(t *testing.T) {
281 var o testGoReflectMethod_O
282 o.Get()
283 vm := New()
284 vm.Set("o", o)
285 _, err := vm.RunString(`o.Get()`)
286 if err != nil {
287 t.Fatal(err)
288 }
289 _, err = vm.RunString(`o.Method()`)
290 if err != nil {
291 t.Fatal(err)
292 }
293
294 var b testBoolS
295 vm.Set("b", b)
296 _, err = vm.RunString(`b.Method()`)
297 if err != nil {
298 t.Fatal(err)
299 }
300 }
301
302 func TestGoReflectStructField(t *testing.T) {
303 type S struct {
304 F testGoReflectMethod_O
305 B testBoolS
306 }
307 var s S
308 vm := New()
309 vm.Set("s", &s)
310
311 const SCRIPT = `
312 s.F.Set("Test");
313 assert.sameValue(s.F.Method(""), "Test", "1");
314
315 s.B = true;
316 assert.sameValue(s.B.Method(), true, "2");
317
318 assert.sameValue(s.B.toString(), "B", "3");
319 `
320
321 vm.testScriptWithTestLib(SCRIPT, _undefined, t)
322 }
323
324 func TestGoReflectProp(t *testing.T) {
325 const SCRIPT = `
326 var d1 = Object.getOwnPropertyDescriptor(o, "Get");
327 var d2 = Object.getOwnPropertyDescriptor(o, "Test");
328 !d1.writable && !d1.configurable && d2.writable && !d2.configurable;
329 `
330
331 o := testGoReflectMethod_O{
332 field: "test",
333 }
334
335 r := New()
336 r.Set("o", &o)
337 v, err := r.RunString(SCRIPT)
338 if err != nil {
339 t.Fatal(err)
340 }
341
342 if !v.StrictEquals(valueTrue) {
343 t.Fatalf("Expected true, got %v", v)
344 }
345 }
346
347 func TestGoReflectRedefineFieldSuccess(t *testing.T) {
348 const SCRIPT = `
349 Object.defineProperty(o, "Test", {value: "AAA"}) === o;
350 `
351
352 o := testGoReflectMethod_O{}
353
354 r := New()
355 r.Set("o", &o)
356 v, err := r.RunString(SCRIPT)
357 if err != nil {
358 t.Fatal(err)
359 }
360
361 if !v.StrictEquals(valueTrue) {
362 t.Fatalf("Expected true, got %v", v)
363 }
364
365 if o.Test != "AAA" {
366 t.Fatalf("Expected 'AAA', got '%s'", o.Test)
367 }
368
369 }
370
371 func TestGoReflectRedefineFieldNonWritable(t *testing.T) {
372 const SCRIPT = `
373 var thrown = false;
374 try {
375 Object.defineProperty(o, "Test", {value: "AAA", writable: false});
376 } catch (e) {
377 if (e instanceof TypeError) {
378 thrown = true;
379 } else {
380 throw e;
381 }
382 }
383 thrown;
384 `
385
386 o := testGoReflectMethod_O{Test: "Test"}
387
388 r := New()
389 r.Set("o", &o)
390 v, err := r.RunString(SCRIPT)
391 if err != nil {
392 t.Fatal(err)
393 }
394
395 if !v.StrictEquals(valueTrue) {
396 t.Fatalf("Expected true, got %v", v)
397 }
398
399 if o.Test != "Test" {
400 t.Fatalf("Expected 'Test', got: '%s'", o.Test)
401 }
402 }
403
404 func TestGoReflectRedefineFieldConfigurable(t *testing.T) {
405 const SCRIPT = `
406 var thrown = false;
407 try {
408 Object.defineProperty(o, "Test", {value: "AAA", configurable: true});
409 } catch (e) {
410 if (e instanceof TypeError) {
411 thrown = true;
412 } else {
413 throw e;
414 }
415 }
416 thrown;
417 `
418
419 o := testGoReflectMethod_O{Test: "Test"}
420
421 r := New()
422 r.Set("o", &o)
423 v, err := r.RunString(SCRIPT)
424 if err != nil {
425 t.Fatal(err)
426 }
427
428 if !v.StrictEquals(valueTrue) {
429 t.Fatalf("Expected true, got %v", v)
430 }
431
432 if o.Test != "Test" {
433 t.Fatalf("Expected 'Test', got: '%s'", o.Test)
434 }
435 }
436
437 func TestGoReflectRedefineMethod(t *testing.T) {
438 const SCRIPT = `
439 var thrown = false;
440 try {
441 Object.defineProperty(o, "Method", {value: "AAA", configurable: true});
442 } catch (e) {
443 if (e instanceof TypeError) {
444 thrown = true;
445 } else {
446 throw e;
447 }
448 }
449 thrown;
450 `
451
452 o := testGoReflectMethod_O{Test: "Test"}
453
454 r := New()
455 r.Set("o", &o)
456 v, err := r.RunString(SCRIPT)
457 if err != nil {
458 t.Fatal(err)
459 }
460
461 if !v.StrictEquals(valueTrue) {
462 t.Fatalf("Expected true, got %v", v)
463 }
464 }
465
466 func TestGoReflectEmbeddedStruct(t *testing.T) {
467 const SCRIPT = `
468 if (o.ParentField2 !== "ParentField2") {
469 throw new Error("ParentField2 = " + o.ParentField2);
470 }
471
472 if (o.Parent.ParentField2 !== 2) {
473 throw new Error("o.Parent.ParentField2 = " + o.Parent.ParentField2);
474 }
475
476 if (o.ParentField1 !== 1) {
477 throw new Error("o.ParentField1 = " + o.ParentField1);
478
479 }
480
481 if (o.ChildField !== 3) {
482 throw new Error("o.ChildField = " + o.ChildField);
483 }
484
485 var keys = {};
486 for (var k in o) {
487 if (keys[k]) {
488 throw new Error("Duplicate key: " + k);
489 }
490 keys[k] = true;
491 }
492
493 var expectedKeys = ["ParentField2", "ParentField1", "Parent", "ChildField"];
494 for (var i in expectedKeys) {
495 if (!keys[expectedKeys[i]]) {
496 throw new Error("Missing key in enumeration: " + expectedKeys[i]);
497 }
498 delete keys[expectedKeys[i]];
499 }
500
501 var remainingKeys = Object.keys(keys);
502 if (remainingKeys.length > 0) {
503 throw new Error("Unexpected keys: " + remainingKeys);
504 }
505
506 o.ParentField2 = "ParentField22";
507 o.Parent.ParentField2 = 22;
508 o.ParentField1 = 11;
509 o.ChildField = 33;
510 `
511
512 type Parent struct {
513 ParentField1 int
514 ParentField2 int
515 }
516
517 type Child struct {
518 ParentField2 string
519 Parent
520 ChildField int
521 }
522
523 vm := New()
524 o := Child{
525 Parent: Parent{
526 ParentField1: 1,
527 ParentField2: 2,
528 },
529 ParentField2: "ParentField2",
530 ChildField: 3,
531 }
532 vm.Set("o", &o)
533
534 _, err := vm.RunString(SCRIPT)
535 if err != nil {
536 t.Fatal(err)
537 }
538
539 if o.ParentField2 != "ParentField22" {
540 t.Fatalf("ParentField2 = %q", o.ParentField2)
541 }
542
543 if o.Parent.ParentField2 != 22 {
544 t.Fatalf("Parent.ParentField2 = %d", o.Parent.ParentField2)
545 }
546
547 if o.ParentField1 != 11 {
548 t.Fatalf("ParentField1 = %d", o.ParentField1)
549 }
550
551 if o.ChildField != 33 {
552 t.Fatalf("ChildField = %d", o.ChildField)
553 }
554 }
555
556 type jsonTagNamer struct{}
557
558 func (jsonTagNamer) FieldName(_ reflect.Type, field reflect.StructField) string {
559 if jsonTag := field.Tag.Get("json"); jsonTag != "" {
560 return jsonTag
561 }
562 return field.Name
563 }
564
565 func (jsonTagNamer) MethodName(_ reflect.Type, method reflect.Method) string {
566 return method.Name
567 }
568
569 func TestGoReflectCustomNaming(t *testing.T) {
570
571 type testStructWithJsonTags struct {
572 A string `json:"b"`
573 }
574
575 o := &testStructWithJsonTags{"Hello world"}
576 r := New()
577 r.SetFieldNameMapper(&jsonTagNamer{})
578 r.Set("fn", func() *testStructWithJsonTags { return o })
579
580 t.Run("get property", func(t *testing.T) {
581 v, err := r.RunString(`fn().b`)
582 if err != nil {
583 t.Fatal(err)
584 }
585 if !v.StrictEquals(newStringValue(o.A)) {
586 t.Fatalf("Expected %q, got %v", o.A, v)
587 }
588 })
589
590 t.Run("set property", func(t *testing.T) {
591 _, err := r.RunString(`fn().b = "Hello universe"`)
592 if err != nil {
593 t.Fatal(err)
594 }
595 if o.A != "Hello universe" {
596 t.Fatalf("Expected \"Hello universe\", got %q", o.A)
597 }
598 })
599
600 t.Run("enumerate properties", func(t *testing.T) {
601 v, err := r.RunString(`Object.keys(fn())`)
602 if err != nil {
603 t.Fatal(err)
604 }
605 if !reflect.DeepEqual(v.Export(), []interface{}{"b"}) {
606 t.Fatalf("Expected [\"b\"], got %v", v.Export())
607 }
608 })
609 }
610
611 func TestGoReflectCustomObjNaming(t *testing.T) {
612
613 type testStructWithJsonTags struct {
614 A string `json:"b"`
615 }
616
617 r := New()
618 r.SetFieldNameMapper(&jsonTagNamer{})
619
620 t.Run("Set object in slice", func(t *testing.T) {
621 testSlice := &[]testStructWithJsonTags{{"Hello world"}}
622 r.Set("testslice", testSlice)
623 _, err := r.RunString(`testslice[0] = {b:"setted"}`)
624 if err != nil {
625 t.Fatal(err)
626 }
627 if (*testSlice)[0].A != "setted" {
628 t.Fatalf("Expected \"setted\", got %q", (*testSlice)[0])
629 }
630 })
631
632 t.Run("Set object in map", func(t *testing.T) {
633 testMap := map[string]testStructWithJsonTags{"key": {"Hello world"}}
634 r.Set("testmap", testMap)
635 _, err := r.RunString(`testmap["key"] = {b:"setted"}`)
636 if err != nil {
637 t.Fatal(err)
638 }
639 if testMap["key"].A != "setted" {
640 t.Fatalf("Expected \"setted\", got %q", testMap["key"])
641 }
642 })
643
644 t.Run("Add object to map", func(t *testing.T) {
645 testMap := map[string]testStructWithJsonTags{}
646 r.Set("testmap", testMap)
647 _, err := r.RunString(`testmap["newkey"] = {b:"setted"}`)
648 if err != nil {
649 t.Fatal(err)
650 }
651 if testMap["newkey"].A != "setted" {
652 t.Fatalf("Expected \"setted\", got %q", testMap["newkey"])
653 }
654 })
655 }
656
657 type fieldNameMapper1 struct{}
658
659 func (fieldNameMapper1) FieldName(_ reflect.Type, f reflect.StructField) string {
660 return strings.ToLower(f.Name)
661 }
662
663 func (fieldNameMapper1) MethodName(_ reflect.Type, m reflect.Method) string {
664 return m.Name
665 }
666
667 func TestNonStructAnonFields(t *testing.T) {
668 type Test1 struct {
669 M bool
670 }
671 type test3 []int
672 type Test4 []int
673 type Test2 struct {
674 test3
675 Test4
676 *Test1
677 }
678
679 const SCRIPT = `
680 JSON.stringify(a);
681 a.m && a.test3 === undefined && a.test4.length === 2
682 `
683 vm := New()
684 vm.SetFieldNameMapper(fieldNameMapper1{})
685 vm.Set("a", &Test2{Test1: &Test1{M: true}, Test4: []int{1, 2}, test3: nil})
686 v, err := vm.RunString(SCRIPT)
687 if err != nil {
688 t.Fatal(err)
689 }
690 if !v.StrictEquals(valueTrue) {
691 t.Fatalf("Unexepected result: %v", v)
692 }
693 }
694
695 func TestStructNonAddressable(t *testing.T) {
696 type S struct {
697 Field int
698 }
699
700 const SCRIPT = `
701 "use strict";
702
703 if (!Object.getOwnPropertyDescriptor(s, "Field").writable) {
704 throw new Error("s.Field is non-writable");
705 }
706
707 if (!Object.getOwnPropertyDescriptor(s1, "Field").writable) {
708 throw new Error("s1.Field is non-writable");
709 }
710
711 s1.Field = 42;
712 s.Field = 43;
713 s;
714 `
715
716 var s S
717 vm := New()
718 vm.Set("s", s)
719 vm.Set("s1", &s)
720 v, err := vm.RunString(SCRIPT)
721 if err != nil {
722 t.Fatal(err)
723 }
724 exp := v.Export()
725 if s1, ok := exp.(S); ok {
726 if s1.Field != 43 {
727 t.Fatal(s1)
728 }
729 } else {
730 t.Fatalf("Wrong type: %T", exp)
731 }
732 if s.Field != 42 {
733 t.Fatalf("Unexpected s.Field value: %d", s.Field)
734 }
735 }
736
737 type testFieldMapper struct {
738 }
739
740 func (testFieldMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
741 if tag := f.Tag.Get("js"); tag != "" {
742 if tag == "-" {
743 return ""
744 }
745 return tag
746 }
747
748 return f.Name
749 }
750
751 func (testFieldMapper) MethodName(_ reflect.Type, m reflect.Method) string {
752 return m.Name
753 }
754
755 func TestHidingAnonField(t *testing.T) {
756 type InnerType struct {
757 AnotherField string
758 }
759
760 type OuterType struct {
761 InnerType `js:"-"`
762 SomeField string
763 }
764
765 const SCRIPT = `
766 var a = Object.getOwnPropertyNames(o);
767 if (a.length !== 2) {
768 throw new Error("unexpected length: " + a.length);
769 }
770
771 if (a.indexOf("SomeField") === -1) {
772 throw new Error("no SomeField");
773 }
774
775 if (a.indexOf("AnotherField") === -1) {
776 throw new Error("no SomeField");
777 }
778 `
779
780 var o OuterType
781
782 vm := New()
783 vm.SetFieldNameMapper(testFieldMapper{})
784 vm.Set("o", &o)
785
786 _, err := vm.RunString(SCRIPT)
787 if err != nil {
788 t.Fatal(err)
789 }
790 }
791
792 func TestFieldOverriding(t *testing.T) {
793 type InnerType struct {
794 AnotherField string
795 AnotherField1 string
796 }
797
798 type OuterType struct {
799 InnerType `js:"-"`
800 SomeField string
801 AnotherField string `js:"-"`
802 AnotherField1 string
803 }
804
805 const SCRIPT = `
806 if (o.SomeField !== "SomeField") {
807 throw new Error("SomeField");
808 }
809
810 if (o.AnotherField !== "AnotherField inner") {
811 throw new Error("AnotherField");
812 }
813
814 if (o.AnotherField1 !== "AnotherField1 outer") {
815 throw new Error("AnotherField1");
816 }
817
818 if (o.InnerType) {
819 throw new Error("InnerType is present");
820 }
821 `
822
823 o := OuterType{
824 InnerType: InnerType{
825 AnotherField: "AnotherField inner",
826 AnotherField1: "AnotherField1 inner",
827 },
828 SomeField: "SomeField",
829 AnotherField: "AnotherField outer",
830 AnotherField1: "AnotherField1 outer",
831 }
832
833 vm := New()
834 vm.SetFieldNameMapper(testFieldMapper{})
835 vm.Set("o", &o)
836
837 _, err := vm.RunString(SCRIPT)
838 if err != nil {
839 t.Fatal(err)
840 }
841 }
842
843 func TestDefinePropertyUnexportedJsName(t *testing.T) {
844 type T struct {
845 Field int
846 unexported int
847 }
848
849 vm := New()
850 vm.SetFieldNameMapper(fieldNameMapper1{})
851 vm.Set("f", &T{unexported: 0})
852
853 _, err := vm.RunString(`
854 "use strict";
855 Object.defineProperty(f, "field", {value: 42});
856 if (f.field !== 42) {
857 throw new Error("Unexpected value: " + f.field);
858 }
859 if (f.hasOwnProperty("unexported")) {
860 throw new Error("hasOwnProperty('unexported') is true");
861 }
862 var thrown;
863 try {
864 Object.defineProperty(f, "unexported", {value: 1});
865 } catch (e) {
866 thrown = e;
867 }
868 if (!(thrown instanceof TypeError)) {
869 throw new Error("Unexpected error: ", thrown);
870 }
871 `)
872 if err != nil {
873 t.Fatal(err)
874 }
875 }
876
877 type fieldNameMapperToLower struct{}
878
879 func (fieldNameMapperToLower) FieldName(_ reflect.Type, f reflect.StructField) string {
880 return strings.ToLower(f.Name)
881 }
882
883 func (fieldNameMapperToLower) MethodName(_ reflect.Type, m reflect.Method) string {
884 return strings.ToLower(m.Name)
885 }
886
887 func TestHasOwnPropertyUnexportedJsName(t *testing.T) {
888 vm := New()
889 vm.SetFieldNameMapper(fieldNameMapperToLower{})
890 vm.Set("f", &testGoReflectMethod_O{})
891
892 _, err := vm.RunString(`
893 "use strict";
894 if (!f.hasOwnProperty("test")) {
895 throw new Error("hasOwnProperty('test') returned false");
896 }
897 if (!f.hasOwnProperty("method")) {
898 throw new Error("hasOwnProperty('method') returned false");
899 }
900 `)
901 if err != nil {
902 t.Fatal(err)
903 }
904 }
905
906 func BenchmarkGoReflectGet(b *testing.B) {
907 type parent struct {
908 field, Test1, Test2, Test3, Test4, Test5, Test string
909 }
910
911 type child struct {
912 parent
913 Test6 string
914 }
915
916 b.StopTimer()
917 vm := New()
918
919 b.StartTimer()
920 for i := 0; i < b.N; i++ {
921 v := vm.ToValue(child{parent: parent{Test: "Test", field: ""}}).(*Object)
922 v.Get("Test")
923 }
924 }
925
926 func TestNestedStructSet(t *testing.T) {
927 type B struct {
928 Field int
929 }
930 type A struct {
931 B B
932 }
933
934 const SCRIPT = `
935 'use strict';
936 a.B.Field++;
937 if (a1.B.Field != 1) {
938 throw new Error("a1.B.Field = " + a1.B.Field);
939 }
940 var d = Object.getOwnPropertyDescriptor(a1.B, "Field");
941 if (!d.writable) {
942 throw new Error("a1.B is not writable");
943 }
944 a1.B.Field = 42;
945 a1;
946 `
947 a := A{
948 B: B{
949 Field: 1,
950 },
951 }
952 vm := New()
953 vm.Set("a", &a)
954 vm.Set("a1", a)
955 v, err := vm.RunString(SCRIPT)
956 if err != nil {
957 t.Fatal(err)
958 }
959 exp := v.Export()
960 if v, ok := exp.(A); ok {
961 if v.B.Field != 42 {
962 t.Fatal(v)
963 }
964 } else {
965 t.Fatalf("Wrong type: %T", exp)
966 }
967
968 if v := a.B.Field; v != 2 {
969 t.Fatalf("Unexpected a.B.Field: %d", v)
970 }
971 }
972
973 func TestStructNonAddressableAnonStruct(t *testing.T) {
974
975 type C struct {
976 Z int64
977 X string
978 }
979
980 type B struct {
981 C
982 Y string
983 }
984
985 type A struct {
986 B B
987 }
988
989 a := A{
990 B: B{
991 C: C{
992 Z: 1,
993 X: "X2",
994 },
995 Y: "Y3",
996 },
997 }
998 const SCRIPT = `
999 "use strict";
1000 var s = JSON.stringify(a);
1001 s;
1002 `
1003
1004 vm := New()
1005 vm.Set("a", &a)
1006 v, err := vm.RunString(SCRIPT)
1007 if err != nil {
1008 t.Fatal(err)
1009 }
1010
1011 expected := `{"B":{"C":{"Z":1,"X":"X2"},"Z":1,"X":"X2","Y":"Y3"}}`
1012 if expected != v.String() {
1013 t.Fatalf("Expected '%s', got '%s'", expected, v.String())
1014 }
1015
1016 }
1017
1018 func TestTagFieldNameMapperInvalidId(t *testing.T) {
1019 vm := New()
1020 vm.SetFieldNameMapper(TagFieldNameMapper("json", true))
1021 type S struct {
1022 Field int `json:"-"`
1023 }
1024 vm.Set("s", S{Field: 42})
1025 res, err := vm.RunString(`s.hasOwnProperty("field") || s.hasOwnProperty("Field")`)
1026 if err != nil {
1027 t.Fatal(err)
1028 }
1029 if res != valueFalse {
1030 t.Fatalf("Unexpected result: %v", res)
1031 }
1032 }
1033
1034 func TestPrimitivePtr(t *testing.T) {
1035 vm := New()
1036 s := "test"
1037 vm.Set("s", &s)
1038 res, err := vm.RunString(`s instanceof String && s == "test"`)
1039 if err != nil {
1040 t.Fatal(err)
1041 }
1042 if v := res.ToBoolean(); !v {
1043 t.Fatalf("value: %#v", res)
1044 }
1045 s = "test1"
1046 res, err = vm.RunString(`s == "test1"`)
1047 if err != nil {
1048 t.Fatal(err)
1049 }
1050 if v := res.ToBoolean(); !v {
1051 t.Fatalf("value: %#v", res)
1052 }
1053 }
1054
1055 func TestStringer(t *testing.T) {
1056 vm := New()
1057 vm.Set("e", errors.New("test"))
1058 res, err := vm.RunString("e.toString()")
1059 if err != nil {
1060 t.Fatal(err)
1061 }
1062 if v := res.Export(); v != "test" {
1063 t.Fatalf("v: %v", v)
1064 }
1065 }
1066
1067 func ExampleTagFieldNameMapper() {
1068 vm := New()
1069 vm.SetFieldNameMapper(TagFieldNameMapper("json", true))
1070 type S struct {
1071 Field int `json:"field"`
1072 }
1073 vm.Set("s", S{Field: 42})
1074 res, _ := vm.RunString(`s.field`)
1075 fmt.Println(res.Export())
1076
1077 }
1078
1079 func ExampleUncapFieldNameMapper() {
1080 vm := New()
1081 s := testGoReflectMethod_O{
1082 Test: "passed",
1083 }
1084 vm.SetFieldNameMapper(UncapFieldNameMapper())
1085 vm.Set("s", s)
1086 res, _ := vm.RunString(`s.test + " and " + s.method("passed too")`)
1087 fmt.Println(res.Export())
1088
1089 }
1090
1091 func TestGoReflectWithProto(t *testing.T) {
1092 type S struct {
1093 Field int
1094 }
1095 var s S
1096 vm := New()
1097 vm.Set("s", &s)
1098 vm.testScriptWithTestLib(`
1099 (function() {
1100 'use strict';
1101 var proto = {
1102 Field: "protoField",
1103 test: 42
1104 };
1105 var test1Holder;
1106 Object.defineProperty(proto, "test1", {
1107 set: function(v) {
1108 test1Holder = v;
1109 },
1110 get: function() {
1111 return test1Holder;
1112 }
1113 });
1114 Object.setPrototypeOf(s, proto);
1115 assert.sameValue(s.Field, 0, "s.Field");
1116 s.Field = 2;
1117 assert.sameValue(s.Field, 2, "s.Field");
1118 assert.sameValue(s.test, 42, "s.test");
1119 assert.throws(TypeError, function() {
1120 Object.defineProperty(s, "test", {value: 43});
1121 });
1122 test1Holder = 1;
1123 assert.sameValue(s.test1, 1, "s.test1");
1124 s.test1 = 2;
1125 assert.sameValue(test1Holder, 2, "test1Holder");
1126 })();
1127 `, _undefined, t)
1128 }
1129
1130 func TestGoReflectSymbols(t *testing.T) {
1131 type S struct {
1132 Field int
1133 }
1134 var s S
1135 vm := New()
1136 vm.Set("s", &s)
1137 _, err := vm.RunString(`
1138 'use strict';
1139 var sym = Symbol(66);
1140 s[sym] = "Test";
1141 if (s[sym] !== "Test") {
1142 throw new Error("s[sym]=" + s[sym]);
1143 }
1144 `)
1145 if err != nil {
1146 t.Fatal(err)
1147 }
1148 }
1149
1150 func TestGoReflectSymbolEqualityQuirk(t *testing.T) {
1151 type Field struct {
1152 }
1153 type S struct {
1154 Field *Field
1155 }
1156 var s = S{
1157 Field: &Field{},
1158 }
1159 vm := New()
1160 vm.Set("s", &s)
1161 res, err := vm.RunString(`
1162 var sym = Symbol(66);
1163 var field1 = s.Field;
1164 field1[sym] = true;
1165 var field2 = s.Field;
1166 // Because a wrapper is created every time the property is accessed
1167 // field1 and field2 will be different instances of the wrapper.
1168 // Symbol properties only exist in the wrapper, they cannot be placed into the original Go value,
1169 // hence the following:
1170 field1 === field2 && field1[sym] === true && field2[sym] === undefined;
1171 `)
1172 if err != nil {
1173 t.Fatal(err)
1174 }
1175 if res != valueTrue {
1176 t.Fatal(res)
1177 }
1178 }
1179
1180 func TestGoObj__Proto__(t *testing.T) {
1181 type S struct {
1182 Field int
1183 }
1184 vm := New()
1185 vm.Set("s", S{})
1186 vm.Set("m", map[string]interface{}{})
1187 vm.Set("mr", map[int]string{})
1188 vm.Set("a", []interface{}{})
1189 vm.Set("ar", []string{})
1190 _, err := vm.RunString(`
1191 function f(s, expectedCtor, prefix) {
1192 if (s.__proto__ !== expectedCtor.prototype) {
1193 throw new Error(prefix + ": __proto__: " + s.__proto__);
1194 }
1195 s.__proto__ = null;
1196 if (s.__proto__ !== undefined) { // as there is no longer a prototype, there is no longer the __proto__ property
1197 throw new Error(prefix + ": __proto__ is not undefined: " + s.__proto__);
1198 }
1199 var proto = Object.getPrototypeOf(s);
1200 if (proto !== null) {
1201 throw new Error(prefix + ": proto is not null: " + proto);
1202 }
1203 }
1204 f(s, Object, "struct");
1205 f(m, Object, "simple map");
1206 f(mr, Object, "reflect map");
1207 f(a, Array, "slice");
1208 f(ar, Array, "reflect slice");
1209 `)
1210 if err != nil {
1211 t.Fatal(err)
1212 }
1213 }
1214
1215 func TestGoReflectUnicodeProps(t *testing.T) {
1216 type S struct {
1217 Тест string
1218 }
1219 vm := New()
1220 var s S
1221 vm.Set("s", &s)
1222 _, err := vm.RunString(`
1223 if (!s.hasOwnProperty("Тест")) {
1224 throw new Error("hasOwnProperty");
1225 }
1226 `)
1227 if err != nil {
1228 t.Fatal(err)
1229 }
1230 }
1231
1232 func TestGoReflectPreserveType(t *testing.T) {
1233 vm := New()
1234 var expect = time.Duration(math.MaxInt64)
1235 vm.Set(`make`, func() time.Duration {
1236 return expect
1237 })
1238 vm.Set(`handle`, func(d time.Duration) {
1239 if d.String() != expect.String() {
1240 t.Fatal(`expect`, expect, `, but get`, d)
1241 }
1242 })
1243 _, e := vm.RunString(`
1244 var d=make()
1245 handle(d)
1246 `)
1247 if e != nil {
1248 t.Fatal(e)
1249 }
1250 }
1251
1252 func TestGoReflectCopyOnWrite(t *testing.T) {
1253 type Inner struct {
1254 Field int
1255 }
1256 type S struct {
1257 I Inner
1258 }
1259 var s S
1260 s.I.Field = 1
1261
1262 vm := New()
1263 vm.Set("s", &s)
1264 _, err := vm.RunString(`
1265 if (s.I.Field !== 1) {
1266 throw new Error("s.I.Field: " + s.I.Field);
1267 }
1268
1269 let tmp = s.I; // tmp becomes a reference to s.I
1270 if (tmp.Field !== 1) {
1271 throw new Error("tmp.Field: " + tmp.Field);
1272 }
1273
1274 s.I.Field = 2;
1275 if (s.I.Field !== 2) {
1276 throw new Error("s.I.Field (1): " + s.I.Field);
1277 }
1278 if (tmp.Field !== 2) {
1279 throw new Error("tmp.Field (1): " + tmp.Field);
1280 }
1281
1282 s.I = {Field: 3}; // at this point tmp is changed to a copy
1283 if (s.I.Field !== 3) {
1284 throw new Error("s.I.Field (2): " + s.I.Field);
1285 }
1286 if (tmp.Field !== 2) {
1287 throw new Error("tmp.Field (2): " + tmp.Field);
1288 }
1289 `)
1290
1291 if err != nil {
1292 t.Fatal(err)
1293 }
1294 }
1295
1296 func TestReflectSetReflectValue(t *testing.T) {
1297 o := []testGoReflectMethod_O{{}}
1298 vm := New()
1299 vm.Set("o", o)
1300 _, err := vm.RunString(`
1301 const t = o[0];
1302 t.Set("a");
1303 o[0] = {};
1304 o[0].Set("b");
1305 if (t.Get() !== "a") {
1306 throw new Error();
1307 }
1308 `)
1309
1310 if err != nil {
1311 t.Fatal(err)
1312 }
1313 }
1314
1315 func TestReflectOverwriteReflectMap(t *testing.T) {
1316 vm := New()
1317 type S struct {
1318 M map[int]interface{}
1319 }
1320 var s S
1321 s.M = map[int]interface{}{
1322 0: true,
1323 }
1324 vm.Set("s", &s)
1325 _, err := vm.RunString(`
1326 s.M = {1: false};
1327 `)
1328 if err != nil {
1329 t.Fatal(err)
1330 }
1331 if _, exists := s.M[0]; exists {
1332 t.Fatal(s)
1333 }
1334 }
1335
1336 type testBoolS bool
1337
1338 func (testBoolS) String() string {
1339 return "B"
1340 }
1341
1342 type testIntS int
1343
1344 func (testIntS) String() string {
1345 return "I"
1346 }
1347
1348 type testStringS string
1349
1350 func (testStringS) String() string {
1351 return "S"
1352 }
1353
1354 func TestGoReflectToPrimitive(t *testing.T) {
1355 vm := New()
1356
1357 f := func(expr string, expected Value, t *testing.T) {
1358 v, err := vm.RunString(expr)
1359 if err != nil {
1360 t.Fatal(err)
1361 }
1362 if IsNaN(expected) {
1363 if IsNaN(v) {
1364 return
1365 }
1366 } else {
1367 if v.StrictEquals(expected) {
1368 return
1369 }
1370 }
1371 t.Fatalf("%s: expected: %v, actual: %v", expr, expected, v)
1372 }
1373
1374 t.Run("Not Stringers", func(t *testing.T) {
1375 type Bool bool
1376 var b Bool = true
1377
1378 t.Run("Bool", func(t *testing.T) {
1379 vm.Set("b", b)
1380 f("+b", intToValue(1), t)
1381 f("`${b}`", asciiString("true"), t)
1382 f("b.toString()", asciiString("true"), t)
1383 f("b.valueOf()", valueTrue, t)
1384 })
1385
1386 t.Run("*Bool", func(t *testing.T) {
1387 vm.Set("b", &b)
1388 f("+b", intToValue(1), t)
1389 f("`${b}`", asciiString("true"), t)
1390 f("b.toString()", asciiString("true"), t)
1391 f("b.valueOf()", valueTrue, t)
1392 })
1393
1394 type Int int
1395 var i Int = 1
1396
1397 t.Run("Int", func(t *testing.T) {
1398 vm.Set("i", i)
1399 f("+i", intToValue(1), t)
1400 f("`${i}`", asciiString("1"), t)
1401 f("i.toString()", asciiString("1"), t)
1402 f("i.valueOf()", intToValue(1), t)
1403 })
1404
1405 t.Run("*Int", func(t *testing.T) {
1406 vm.Set("i", &i)
1407 f("+i", intToValue(1), t)
1408 f("`${i}`", asciiString("1"), t)
1409 f("i.toString()", asciiString("1"), t)
1410 f("i.valueOf()", intToValue(1), t)
1411 })
1412
1413 type Uint uint
1414 var ui Uint = 1
1415
1416 t.Run("Uint", func(t *testing.T) {
1417 vm.Set("ui", ui)
1418 f("+ui", intToValue(1), t)
1419 f("`${ui}`", asciiString("1"), t)
1420 f("ui.toString()", asciiString("1"), t)
1421 f("ui.valueOf()", intToValue(1), t)
1422 })
1423
1424 t.Run("*Uint", func(t *testing.T) {
1425 vm.Set("ui", &i)
1426 f("+ui", intToValue(1), t)
1427 f("`${ui}`", asciiString("1"), t)
1428 f("ui.toString()", asciiString("1"), t)
1429 f("ui.valueOf()", intToValue(1), t)
1430 })
1431
1432 type Float float64
1433 var fl Float = 1.1
1434
1435 t.Run("Float", func(t *testing.T) {
1436 vm.Set("fl", fl)
1437 f("+fl", floatToValue(1.1), t)
1438 f("`${fl}`", asciiString("1.1"), t)
1439 f("fl.toString()", asciiString("1.1"), t)
1440 f("fl.valueOf()", floatToValue(1.1), t)
1441 })
1442
1443 t.Run("*Float", func(t *testing.T) {
1444 vm.Set("fl", &fl)
1445 f("+fl", floatToValue(1.1), t)
1446 f("`${fl}`", asciiString("1.1"), t)
1447 f("fl.toString()", asciiString("1.1"), t)
1448 f("fl.valueOf()", floatToValue(1.1), t)
1449 })
1450
1451 fl = Float(math.Inf(1))
1452 t.Run("FloatInf", func(t *testing.T) {
1453 vm.Set("fl", fl)
1454 f("+fl", _positiveInf, t)
1455 f("fl.toString()", asciiString("Infinity"), t)
1456 })
1457
1458 type Empty struct{}
1459
1460 var e Empty
1461 t.Run("Empty", func(t *testing.T) {
1462 vm.Set("e", &e)
1463 f("+e", _NaN, t)
1464 f("`${e}`", asciiString("[object Object]"), t)
1465 f("e.toString()", asciiString("[object Object]"), t)
1466 f("e.valueOf()", vm.ToValue(&e), t)
1467 })
1468 })
1469
1470 t.Run("Stringers", func(t *testing.T) {
1471 var b testBoolS = true
1472 t.Run("Bool", func(t *testing.T) {
1473 vm.Set("b", b)
1474 f("`${b}`", asciiString("B"), t)
1475 f("b.toString()", asciiString("B"), t)
1476 f("b.valueOf()", valueTrue, t)
1477 f("+b", intToValue(1), t)
1478 })
1479
1480 t.Run("*Bool", func(t *testing.T) {
1481 vm.Set("b", &b)
1482 f("`${b}`", asciiString("B"), t)
1483 f("b.toString()", asciiString("B"), t)
1484 f("b.valueOf()", valueTrue, t)
1485 f("+b", intToValue(1), t)
1486 })
1487
1488 var i testIntS = 1
1489 t.Run("Int", func(t *testing.T) {
1490 vm.Set("i", i)
1491 f("`${i}`", asciiString("I"), t)
1492 f("i.toString()", asciiString("I"), t)
1493 f("i.valueOf()", intToValue(1), t)
1494 f("+i", intToValue(1), t)
1495 })
1496
1497 t.Run("*Int", func(t *testing.T) {
1498 vm.Set("i", &i)
1499 f("`${i}`", asciiString("I"), t)
1500 f("i.toString()", asciiString("I"), t)
1501 f("i.valueOf()", intToValue(1), t)
1502 f("+i", intToValue(1), t)
1503 })
1504
1505 var s testStringS
1506 t.Run("String", func(t *testing.T) {
1507 vm.Set("s", s)
1508 f("`${s}`", asciiString("S"), t)
1509 f("s.toString()", asciiString("S"), t)
1510 f("s.valueOf()", asciiString("S"), t)
1511 f("+s", _NaN, t)
1512 })
1513
1514 t.Run("*String", func(t *testing.T) {
1515 vm.Set("s", &s)
1516 f("`${s}`", asciiString("S"), t)
1517 f("s.toString()", asciiString("S"), t)
1518 f("s.valueOf()", asciiString("S"), t)
1519 f("+s", _NaN, t)
1520 })
1521 })
1522 }
1523
1524 type testGoReflectFuncRt struct {
1525 }
1526
1527 func (*testGoReflectFuncRt) M(call FunctionCall, r *Runtime) Value {
1528 if r == nil {
1529 panic(typeError("Runtime is nil"))
1530 }
1531 return call.Argument(0)
1532 }
1533
1534 func (*testGoReflectFuncRt) C(call ConstructorCall, r *Runtime) *Object {
1535 if r == nil {
1536 panic(typeError("Runtime is nil in constructor"))
1537 }
1538 call.This.Set("r", call.Argument(0))
1539 return nil
1540 }
1541
1542 func TestGoReflectFuncWithRuntime(t *testing.T) {
1543 vm := New()
1544 var s testGoReflectFuncRt
1545 vm.Set("s", &s)
1546 res, err := vm.RunString("s.M(true)")
1547 if err != nil {
1548 t.Fatal(err)
1549 }
1550 if res != valueTrue {
1551 t.Fatal(res)
1552 }
1553
1554 res, err = vm.RunString("new s.C(true).r")
1555 if err != nil {
1556 t.Fatal(err)
1557 }
1558 if res != valueTrue {
1559 t.Fatal(res)
1560 }
1561 }
1562
1563 func TestGoReflectDefaultToString(t *testing.T) {
1564 var s testStringS
1565 vm := New()
1566 v := vm.ToValue(s).(*Object)
1567 v.Delete("toString")
1568 v.Delete("valueOf")
1569 vm.Set("s", v)
1570 _, err := vm.RunString(`
1571 class S {
1572 toString() {
1573 return "X";
1574 }
1575 }
1576
1577 if (s.toString() !== "S") {
1578 throw new Error(s.toString());
1579 }
1580 if (("" + s) !== "S") {
1581 throw new Error("" + s);
1582 }
1583
1584 Object.setPrototypeOf(s, S.prototype);
1585 if (s.toString() !== "X") {
1586 throw new Error(s.toString());
1587 }
1588 if (("" + s) !== "X") {
1589 throw new Error("" + s);
1590 }
1591 `)
1592 if err != nil {
1593 t.Fatal(err)
1594 }
1595 }
1596
View as plain text