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

     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  }