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) } }