351 lines
6.2 KiB
Go
351 lines
6.2 KiB
Go
|
package goja
|
||
|
|
||
|
import (
|
||
|
"sort"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestGoMapReflectGetSet(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
m.c = m.a + m.b;
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := map[string]string{
|
||
|
"a": "4",
|
||
|
"b": "2",
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
|
||
|
_, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if c := m["c"]; c != "42" {
|
||
|
t.Fatalf("Unexpected value: '%s'", c)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectIntKey(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
m[2] = m[0] + m[1];
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := map[int]int{
|
||
|
0: 40,
|
||
|
1: 2,
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
|
||
|
_, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if c := m[2]; c != 42 {
|
||
|
t.Fatalf("Unexpected value: '%d'", c)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectDelete(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
delete m.a;
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := map[string]string{
|
||
|
"a": "4",
|
||
|
"b": "2",
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
|
||
|
_, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if _, exists := m["a"]; exists {
|
||
|
t.Fatal("a still exists")
|
||
|
}
|
||
|
|
||
|
if b := m["b"]; b != "2" {
|
||
|
t.Fatalf("Unexpected b: '%s'", b)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectJSON(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
function f(m) {
|
||
|
return JSON.stringify(m);
|
||
|
}
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := map[string]string{
|
||
|
"t": "42",
|
||
|
}
|
||
|
_, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
f := vm.Get("f")
|
||
|
if call, ok := AssertFunction(f); ok {
|
||
|
v, err := call(nil, ([]Value{vm.ToValue(m)})...)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if !v.StrictEquals(asciiString(`{"t":"42"}`)) {
|
||
|
t.Fatalf("Unexpected value: %v", v)
|
||
|
}
|
||
|
} else {
|
||
|
t.Fatalf("Not a function: %v", f)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectProto(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
m.hasOwnProperty("t");
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := map[string]string{
|
||
|
"t": "42",
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
v, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type gomapReflect_noMethods map[string]interface{}
|
||
|
type gomapReflect_withMethods map[string]interface{}
|
||
|
|
||
|
func (m gomapReflect_withMethods) Method() bool {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectNoMethods(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
typeof m === "object" && m.hasOwnProperty("t") && m.t === 42;
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := make(gomapReflect_noMethods)
|
||
|
m["t"] = 42
|
||
|
vm.Set("m", m)
|
||
|
v, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectWithMethods(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
typeof m === "object" && !m.hasOwnProperty("t") && m.hasOwnProperty("Method") && m.Method();
|
||
|
`
|
||
|
|
||
|
vm := New()
|
||
|
m := make(gomapReflect_withMethods)
|
||
|
m["t"] = 42
|
||
|
vm.Set("m", m)
|
||
|
v, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectWithProto(t *testing.T) {
|
||
|
vm := New()
|
||
|
m := map[string]string{
|
||
|
"t": "42",
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
vm.testScriptWithTestLib(`
|
||
|
(function() {
|
||
|
'use strict';
|
||
|
var proto = {};
|
||
|
var getterAllowed = false;
|
||
|
var setterAllowed = false;
|
||
|
var tHolder = "proto t";
|
||
|
Object.defineProperty(proto, "t", {
|
||
|
get: function() {
|
||
|
if (!getterAllowed) throw new Error("getter is called");
|
||
|
return tHolder;
|
||
|
},
|
||
|
set: function(v) {
|
||
|
if (!setterAllowed) throw new Error("setter is called");
|
||
|
tHolder = v;
|
||
|
}
|
||
|
});
|
||
|
var t1Holder;
|
||
|
Object.defineProperty(proto, "t1", {
|
||
|
get: function() {
|
||
|
return t1Holder;
|
||
|
},
|
||
|
set: function(v) {
|
||
|
t1Holder = v;
|
||
|
}
|
||
|
});
|
||
|
Object.setPrototypeOf(m, proto);
|
||
|
assert.sameValue(m.t, "42");
|
||
|
m.t = 43;
|
||
|
assert.sameValue(m.t, "43");
|
||
|
t1Holder = "test";
|
||
|
assert.sameValue(m.t1, "test");
|
||
|
m.t1 = "test1";
|
||
|
assert.sameValue(m.t1, "test1");
|
||
|
delete m.t;
|
||
|
getterAllowed = true;
|
||
|
assert.sameValue(m.t, "proto t", "after delete");
|
||
|
setterAllowed = true;
|
||
|
m.t = true;
|
||
|
assert.sameValue(m.t, true, "m.t === true");
|
||
|
assert.sameValue(tHolder, true, "tHolder === true");
|
||
|
Object.preventExtensions(m);
|
||
|
assert.throws(TypeError, function() {
|
||
|
m.t2 = 1;
|
||
|
});
|
||
|
m.t1 = "test2";
|
||
|
assert.sameValue(m.t1, "test2");
|
||
|
})();
|
||
|
`, _undefined, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectProtoProp(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
var proto = {};
|
||
|
Object.defineProperty(proto, "ro", {value: 42});
|
||
|
Object.setPrototypeOf(m, proto);
|
||
|
assert.throws(TypeError, function() {
|
||
|
m.ro = 43;
|
||
|
});
|
||
|
Object.defineProperty(m, "ro", {value: 43});
|
||
|
assert.sameValue(m.ro, "43");
|
||
|
})();
|
||
|
`
|
||
|
|
||
|
r := New()
|
||
|
r.Set("m", map[string]string{})
|
||
|
r.testScriptWithTestLib(SCRIPT, _undefined, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectUnicode(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
Object.setPrototypeOf(m, s);
|
||
|
if (m.Тест !== "passed") {
|
||
|
throw new Error("m.Тест: " + m.Тест);
|
||
|
}
|
||
|
m["é"];
|
||
|
`
|
||
|
type S struct {
|
||
|
Тест string
|
||
|
}
|
||
|
vm := New()
|
||
|
m := map[string]int{
|
||
|
"é": 42,
|
||
|
}
|
||
|
s := S{
|
||
|
Тест: "passed",
|
||
|
}
|
||
|
vm.Set("m", m)
|
||
|
vm.Set("s", &s)
|
||
|
res, err := vm.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if res == nil || !res.StrictEquals(valueInt(42)) {
|
||
|
t.Fatalf("Unexpected value: %v", res)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectStruct(t *testing.T) {
|
||
|
type S struct {
|
||
|
Test int
|
||
|
}
|
||
|
|
||
|
m := map[string]S{
|
||
|
"1": {Test: 1},
|
||
|
}
|
||
|
|
||
|
vm := New()
|
||
|
vm.Set("m", m)
|
||
|
res, err := vm.RunString("m[1].Test = 2; m[1].Test")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if res.Export() != int64(1) {
|
||
|
t.Fatal(res)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectElt(t *testing.T) {
|
||
|
type mapping map[string]interface{}
|
||
|
|
||
|
const SCRIPT = `a.s() && a.t === null && a.t1 === undefined;`
|
||
|
|
||
|
r := New()
|
||
|
|
||
|
r.Set("a", mapping{
|
||
|
"s": func() bool { return true },
|
||
|
"t": nil,
|
||
|
})
|
||
|
|
||
|
r.testScript(SCRIPT, valueTrue, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapReflectKeyToString(t *testing.T) {
|
||
|
vm := New()
|
||
|
|
||
|
test := func(v any, t *testing.T) {
|
||
|
o1 := vm.ToValue(v).ToObject(vm)
|
||
|
keys := o1.Keys()
|
||
|
sort.Strings(keys)
|
||
|
if len(keys) != 2 || keys[0] != "1" || keys[1] != "2" {
|
||
|
t.Fatal(keys)
|
||
|
}
|
||
|
|
||
|
keys1 := o1.self.stringKeys(true, nil)
|
||
|
sort.Slice(keys1, func(a, b int) bool {
|
||
|
return strings.Compare(keys1[a].String(), keys1[b].String()) < 0
|
||
|
})
|
||
|
if len(keys1) != 2 || keys1[0] != asciiString("1") || keys1[1] != asciiString("2") {
|
||
|
t.Fatal(keys1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
t.Run("int", func(t *testing.T) {
|
||
|
m1 := map[int]any{
|
||
|
1: 2,
|
||
|
2: 3,
|
||
|
}
|
||
|
test(m1, t)
|
||
|
})
|
||
|
|
||
|
t.Run("CustomString", func(t *testing.T) {
|
||
|
type CustomString string
|
||
|
m2 := map[CustomString]any{
|
||
|
"1": 2,
|
||
|
"2": 3,
|
||
|
}
|
||
|
test(m2, t)
|
||
|
})
|
||
|
|
||
|
}
|