329 lines
5.7 KiB
Go
329 lines
5.7 KiB
Go
|
package goja
|
||
|
|
||
|
import "testing"
|
||
|
|
||
|
func TestGomapProp(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
o.a + o.b;
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{
|
||
|
"a": 40,
|
||
|
"b": 2,
|
||
|
})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if i := v.ToInteger(); i != 42 {
|
||
|
t.Fatalf("Expected 42, got: %d", i)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGomapEnumerate(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
var hasX = false;
|
||
|
var hasY = false;
|
||
|
for (var key in o) {
|
||
|
switch (key) {
|
||
|
case "x":
|
||
|
if (hasX) {
|
||
|
throw "Already have x";
|
||
|
}
|
||
|
hasX = true;
|
||
|
break;
|
||
|
case "y":
|
||
|
if (hasY) {
|
||
|
throw "Already have y";
|
||
|
}
|
||
|
hasY = true;
|
||
|
break;
|
||
|
default:
|
||
|
throw "Unexpected property: " + key;
|
||
|
}
|
||
|
}
|
||
|
hasX && hasY;
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{
|
||
|
"x": 40,
|
||
|
"y": 2,
|
||
|
})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGomapDeleteWhileEnumerate(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
var hasX = false;
|
||
|
var hasY = false;
|
||
|
for (var key in o) {
|
||
|
switch (key) {
|
||
|
case "x":
|
||
|
if (hasX) {
|
||
|
throw "Already have x";
|
||
|
}
|
||
|
hasX = true;
|
||
|
delete o.y;
|
||
|
break;
|
||
|
case "y":
|
||
|
if (hasY) {
|
||
|
throw "Already have y";
|
||
|
}
|
||
|
hasY = true;
|
||
|
delete o.x;
|
||
|
break;
|
||
|
default:
|
||
|
throw "Unexpected property: " + key;
|
||
|
}
|
||
|
}
|
||
|
hasX && !hasY || hasY && !hasX;
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{
|
||
|
"x": 40,
|
||
|
"y": 2,
|
||
|
})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGomapInstanceOf(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
(o instanceof Object) && !(o instanceof Error);
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGomapTypeOf(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
typeof o;
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(asciiString("object")) {
|
||
|
t.Fatalf("Expected object, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGomapProto(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
o.hasOwnProperty("test");
|
||
|
`
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{
|
||
|
"test": 42,
|
||
|
})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGoMapExtensibility(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
"use strict";
|
||
|
o.test = 42;
|
||
|
Object.preventExtensions(o);
|
||
|
o.test = 43;
|
||
|
try {
|
||
|
o.test1 = 42;
|
||
|
} catch (e) {
|
||
|
if (!(e instanceof TypeError)) {
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
o.test === 43 && o.test1 === undefined;
|
||
|
`
|
||
|
|
||
|
r := New()
|
||
|
r.Set("o", map[string]interface{}{})
|
||
|
v, err := r.RunString(SCRIPT)
|
||
|
if err != nil {
|
||
|
if ex, ok := err.(*Exception); ok {
|
||
|
t.Fatal(ex.String())
|
||
|
} else {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !v.StrictEquals(valueTrue) {
|
||
|
t.Fatalf("Expected true, got %v", v)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func TestGoMapWithProto(t *testing.T) {
|
||
|
vm := New()
|
||
|
m := map[string]interface{}{
|
||
|
"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);
|
||
|
assert.sameValue(tHolder, true);
|
||
|
Object.preventExtensions(m);
|
||
|
assert.throws(TypeError, function() {
|
||
|
m.t2 = 1;
|
||
|
});
|
||
|
m.t1 = "test2";
|
||
|
assert.sameValue(m.t1, "test2");
|
||
|
})();
|
||
|
`, _undefined, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapProtoProp(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]interface{}{})
|
||
|
r.testScriptWithTestLib(SCRIPT, _undefined, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapProtoPropChain(t *testing.T) {
|
||
|
const SCRIPT = `
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
var p1 = Object.create(null);
|
||
|
m.__proto__ = p1;
|
||
|
|
||
|
Object.defineProperty(p1, "test", {
|
||
|
value: 42
|
||
|
});
|
||
|
|
||
|
Object.defineProperty(m, "test", {
|
||
|
value: 43,
|
||
|
writable: true,
|
||
|
});
|
||
|
var o = Object.create(m);
|
||
|
o.test = 44;
|
||
|
assert.sameValue(o.test, 44);
|
||
|
|
||
|
var sym = Symbol(true);
|
||
|
Object.defineProperty(p1, sym, {
|
||
|
value: 42
|
||
|
});
|
||
|
|
||
|
Object.defineProperty(m, sym, {
|
||
|
value: 43,
|
||
|
writable: true,
|
||
|
});
|
||
|
o[sym] = 44;
|
||
|
assert.sameValue(o[sym], 44);
|
||
|
})();
|
||
|
`
|
||
|
|
||
|
r := New()
|
||
|
r.Set("m", map[string]interface{}{})
|
||
|
r.testScriptWithTestLib(SCRIPT, _undefined, t)
|
||
|
}
|
||
|
|
||
|
func TestGoMapUnicode(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]interface{}{
|
||
|
"é": 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)
|
||
|
}
|
||
|
}
|