github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/object_goreflect_test.go (about)

     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"` // <-- script sees field "A" as property "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"` // <-- script sees field "A" as property "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"`) // note non-strict equality
  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  	// Output: 42
  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  	// Output: passed and passed too
  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  }