305 lines
5.6 KiB
Go
305 lines
5.6 KiB
Go
package goja
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestGoReflectArray(t *testing.T) {
|
|
vm := New()
|
|
vm.Set("a", [...]int{1, 2, 3})
|
|
_, err := vm.RunString(`
|
|
if (!Array.isArray(a)) {
|
|
throw new Error("isArray() returned false");
|
|
}
|
|
if (a[0] !== 1 || a[1] !== 2 || a[2] !== 3) {
|
|
throw new Error("Array contents is incorrect");
|
|
}
|
|
if (!a.hasOwnProperty("length")) {
|
|
throw new Error("hasOwnProperty() returned false");
|
|
}
|
|
let desc = Object.getOwnPropertyDescriptor(a, "length");
|
|
if (desc.value !== 3 || desc.writable || desc.enumerable || desc.configurable) {
|
|
throw new Error("incorrect property descriptor: " + JSON.stringify(desc));
|
|
}
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGoReflectArraySort(t *testing.T) {
|
|
vm := New()
|
|
vm.Set("a", [...]int{3, 1, 2})
|
|
v, err := vm.RunString(`
|
|
a.sort();
|
|
if (a[0] !== 1 || a[1] !== 2 || a[2] !== 3) {
|
|
throw new Error(a.toString());
|
|
}
|
|
a;
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
res := v.Export()
|
|
if a, ok := res.([3]int); ok {
|
|
if a[0] != 1 || a[1] != 2 || a[2] != 3 {
|
|
t.Fatal(a)
|
|
}
|
|
} else {
|
|
t.Fatalf("Wrong type: %T", res)
|
|
}
|
|
}
|
|
|
|
func TestGoReflectArrayCopyOnChange(t *testing.T) {
|
|
vm := New()
|
|
|
|
v, err := vm.RunString(`
|
|
a => {
|
|
let tmp = a[0];
|
|
if (tmp !== a[0]) {
|
|
throw new Error("tmp !== a[0]");
|
|
}
|
|
|
|
a[0] = a[1];
|
|
if (tmp === a[0]) {
|
|
throw new Error("tmp === a[0]");
|
|
}
|
|
if (tmp.Test !== "1") {
|
|
throw new Error("tmp.Test: " + tmp.Test + " (" + typeof tmp.Test + ")");
|
|
}
|
|
if (a[0].Test !== "2") {
|
|
throw new Error("a[0].Test: " + a[0].Test);
|
|
}
|
|
|
|
a[0].Test = "3";
|
|
if (a[0].Test !== "3") {
|
|
throw new Error("a[0].Test (1): " + a[0].Test);
|
|
}
|
|
|
|
tmp = a[0];
|
|
tmp.Test = "4";
|
|
if (a[0].Test !== "4") {
|
|
throw new Error("a[0].Test (2): " + a[0].Test);
|
|
}
|
|
|
|
delete a[0];
|
|
if (a[0] && a[0].Test !== "") {
|
|
throw new Error("a[0].Test (3): " + a[0].Test);
|
|
}
|
|
if (tmp.Test !== "4") {
|
|
throw new Error("tmp.Test (1): " + tmp.Test);
|
|
}
|
|
|
|
a[1] = tmp;
|
|
if (a[1].Test !== "4") {
|
|
throw new Error("a[1].Test: " + a[1].Test);
|
|
}
|
|
|
|
// grow
|
|
tmp = a[1];
|
|
a.push(null);
|
|
if (a.length !== 3) {
|
|
throw new Error("a.length after push: " + a.length);
|
|
}
|
|
|
|
tmp.Test = "5";
|
|
if (a[1].Test !== "5") {
|
|
throw new Error("a[1].Test (1): " + a[1].Test);
|
|
}
|
|
|
|
// shrink
|
|
a.length = 1;
|
|
if (a.length !== 1) {
|
|
throw new Error("a.length after shrink: " + a.length);
|
|
}
|
|
|
|
if (tmp.Test !== "5") {
|
|
throw new Error("tmp.Test (shrink): " + tmp.Test);
|
|
}
|
|
}
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
fn, ok := AssertFunction(v)
|
|
if !ok {
|
|
t.Fatal("Not a function")
|
|
}
|
|
|
|
t.Run("[]struct", func(t *testing.T) {
|
|
a := []struct {
|
|
Test string
|
|
}{{"1"}, {"2"}}
|
|
_, err := fn(nil, vm.ToValue(a))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a[0].Test != "" {
|
|
t.Fatalf("a[0]: %#v", a[0])
|
|
}
|
|
|
|
if a[1].Test != "4" {
|
|
t.Fatalf("a0[1]: %#v", a[1])
|
|
}
|
|
})
|
|
|
|
// The copy-on-change mechanism doesn't apply to the types below because the contained values are references.
|
|
// These tests are here for completeness and to prove that the behaviour is consistent.
|
|
|
|
t.Run("[]I", func(t *testing.T) {
|
|
type I interface {
|
|
Get() string
|
|
}
|
|
|
|
a := []I{&testGoReflectMethod_O{Test: "1"}, &testGoReflectMethod_O{Test: "2"}}
|
|
|
|
_, err = fn(nil, vm.ToValue(a))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
|
|
t.Run("[]interface{}", func(t *testing.T) {
|
|
a := []interface{}{&testGoReflectMethod_O{Test: "1"}, &testGoReflectMethod_O{Test: "2"}}
|
|
|
|
_, err = fn(nil, vm.ToValue(a))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCopyOnChangeReflectSlice(t *testing.T) {
|
|
vm := New()
|
|
v, err := vm.RunString(`
|
|
s => {
|
|
s.A.push(1);
|
|
if (s.A.length !== 1) {
|
|
throw new Error("s.A.length: " + s.A.length);
|
|
}
|
|
if (s.A[0] !== 1) {
|
|
throw new Error("s.A[0]: " + s.A[0]);
|
|
}
|
|
let tmp = s.A;
|
|
if (tmp !== s.A) {
|
|
throw new Error("tmp !== s.A");
|
|
}
|
|
s.A = [2];
|
|
if (tmp === s.A) {
|
|
throw new Error("tmp === s.A");
|
|
}
|
|
if (tmp[0] !== 1) {
|
|
throw new Error("tmp[0]: " + tmp[0]);
|
|
}
|
|
if (s.A[0] !== 2) {
|
|
throw new Error("s.A[0] (1): " + s.A[0]);
|
|
}
|
|
}
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fn, ok := AssertFunction(v)
|
|
if !ok {
|
|
t.Fatal("Not a function")
|
|
}
|
|
|
|
t.Run("[]int", func(t *testing.T) {
|
|
type S struct {
|
|
A []int
|
|
}
|
|
var s S
|
|
_, err := fn(nil, vm.ToValue(&s))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(s.A) != 1 {
|
|
t.Fatal(s)
|
|
}
|
|
if s.A[0] != 2 {
|
|
t.Fatal(s.A)
|
|
}
|
|
})
|
|
|
|
t.Run("[]interface{}", func(t *testing.T) {
|
|
type S struct {
|
|
A []interface{}
|
|
}
|
|
var s S
|
|
_, err := fn(nil, vm.ToValue(&s))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(s.A) != 1 {
|
|
t.Fatal(s)
|
|
}
|
|
if s.A[0] != int64(2) {
|
|
t.Fatal(s.A)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCopyOnChangeSort(t *testing.T) {
|
|
a := []struct {
|
|
Test string
|
|
}{{"2"}, {"1"}}
|
|
|
|
vm := New()
|
|
vm.Set("a", &a)
|
|
|
|
_, err := vm.RunString(`
|
|
let a0 = a[0];
|
|
let a1 = a[1];
|
|
a.sort((a, b) => a.Test.localeCompare(b.Test));
|
|
if (a[0].Test !== "1") {
|
|
throw new Error("a[0]: " + a[0]);
|
|
}
|
|
if (a[1].Test !== "2") {
|
|
throw new Error("a[1]: " + a[1]);
|
|
}
|
|
if (a0 !== a[1]) {
|
|
throw new Error("a0 !== a[1]");
|
|
}
|
|
if (a1 !== a[0]) {
|
|
throw new Error("a1 !== a[0]");
|
|
}
|
|
`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if a[0].Test != "1" || a[1].Test != "2" {
|
|
t.Fatal(a)
|
|
}
|
|
}
|
|
|
|
type testStringerArray [8]byte
|
|
|
|
func (a testStringerArray) String() string {
|
|
return "X"
|
|
}
|
|
|
|
func TestReflectArrayToString(t *testing.T) {
|
|
vm := New()
|
|
var a testStringerArray
|
|
vm.Set("a", &a)
|
|
res, err := vm.RunString("`${a}`")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if exp := res.Export(); exp != "X" {
|
|
t.Fatal(exp)
|
|
}
|
|
|
|
var a1 [2]byte
|
|
vm.Set("a", &a1)
|
|
res, err = vm.RunString("`${a}`")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if exp := res.Export(); exp != "0,0" {
|
|
t.Fatal(exp)
|
|
}
|
|
}
|