ai_old/goja/object_goarray_reflect_test.go

305 lines
5.6 KiB
Go
Raw Normal View History

2024-09-20 16:50:35 +08:00
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)
}
}