Make __proto__ more closely match the spec

Create test cases for the "ES6" behavior that matches the spec,
and different tests for the backwardly-compatible behavior.
This commit is contained in:
Gregory Brail 2020-08-24 18:23:59 -07:00 коммит произвёл Greg Brail
Родитель 5a8fed1f5d
Коммит 6cc180bd05
6 изменённых файлов: 107 добавлений и 55 удалений

Просмотреть файл

@ -98,8 +98,13 @@ class SpecialRef extends Ref
} while (search != null);
}
if (type == SPECIAL_PROTO) {
if (cx.getLanguageVersion() < Context.VERSION_ES6 ||
!(target instanceof BaseFunction)) {
if (cx.getLanguageVersion() >= Context.VERSION_ES6) {
if ((value != null && !"object".equals(ScriptRuntime.typeof(value))) ||
!"object".equals(ScriptRuntime.typeof(target))) {
return Undefined.instance;
}
target.setPrototype(obj);
} else {
target.setPrototype(obj);
}
} else {

Просмотреть файл

@ -0,0 +1,41 @@
load('testsrc/assert.js');
// Test old behavior of "__proto__"
// __proto__ can be set to lots of things
let obj = {};
assertTrue(obj.__proto__ === Object.prototype);
obj.__proto__ = undefined;
assertFalse(obj.__proto__ === Object.prototype);
obj.__proto__ = true;
assertFalse(obj.__proto__ === Object.prototype);
obj.__proto__ = 12345;
assertFalse(obj.__proto__ === Object.prototype);
obj.__proto__ = 'foobar';
assertFalse(obj.__proto__ === Object.prototype);
// __proto__ on an object can indeed be set to another object
let prot = {
bar: function() { print('bar'); }
};
obj = {};
assertEquals(prot, obj.__proto__ = prot);
assertFalse(obj.__proto__ === Object.prototype);
assertEquals('function', typeof obj.__proto__.bar);
assertEquals(prot, obj.__proto__);
// __proto__ on an object can be set to null
obj = {};
assertNull(obj.__proto__ = null);
assertFalse(obj.__proto__ === Object.prototype);
//__proto__ setting on a non-object also works
function f() {}
assertTrue(f.__proto__ === Function.prototype);
f.__proto__ = prot;
assertFalse(f.__proto__ === Function.prototype);
assertTrue(f.__proto__ === prot);
f.__proto__ = null;
assertFalse(f.__proto__ === Function.prototype);
"success";

Просмотреть файл

@ -0,0 +1,41 @@
load('testsrc/assert.js');
// Test section B.2.2.1.2 of ECMAScript 6.0, which
// defines the behavior of the "__proto__" special property.
// __proto__ can only be set to an object or to null
let obj = {};
assertTrue(obj.__proto__ === Object.prototype);
assertEquals(undefined, obj.__proto__ = undefined);
assertTrue(obj.__proto__ === Object.prototype);
assertEquals(undefined, obj.__proto__ = true);
assertTrue(obj.__proto__ === Object.prototype);
assertEquals(undefined, obj.__proto__ = 12345);
assertTrue(obj.__proto__ === Object.prototype);
assertEquals(undefined, obj.__proto__ = 'foobar');
assertTrue(obj.__proto__ === Object.prototype);
// __proto__ on an object can indeed be set to another object
let prot = {
bar: function() { print('bar'); }
};
obj = {};
assertEquals(prot, obj.__proto__ = prot);
assertFalse(obj.__proto__ === Object.prototype);
assertEquals('function', typeof obj.__proto__.bar);
assertEquals(prot, obj.__proto__);
// __proto__ on an object can be set to null
obj = {};
assertNull(obj.__proto__ = null);
assertFalse(obj.__proto__ === Object.prototype);
// However, __proto__ setting on a non-object does nothing
function f() {}
assertTrue(f.__proto__ === Function.prototype);
assertEquals(undefined, f.__proto__ = prot);
assertTrue(f.__proto__ === Function.prototype);
assertEquals(undefined, f.__proto__ = null);
assertTrue(f.__proto__ === Function.prototype);
"success";

Просмотреть файл

@ -0,0 +1,9 @@
package org.mozilla.javascript.tests.backwardcompat;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.drivers.LanguageVersion;
import org.mozilla.javascript.drivers.RhinoTest;
@RhinoTest("testsrc/jstests/backwardcompat/backward-proto-property.js")
@LanguageVersion(Context.VERSION_1_8)
public class BackwardProtoPropertyTest {}

Просмотреть файл

@ -1,53 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript.tests.es5;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptableObject;
public class NativeFunctionTest {
private Context cx;
private ScriptableObject scope;
@Before
public void setUp() {
cx = Context.enter();
cx.setLanguageVersion(Context.VERSION_ES6);
scope = cx.initStandardObjects();
}
@After
public void tearDown() {
Context.exit();
}
@Test
public void testFunctionPrototypeNotWritable() {
Object result = cx.evaluateString(
scope, "function e() {}"
+ " e.__proto__ = true;"
+ " e.__proto__ != true;",
"test", 1, null
);
assertEquals(true, result);
}
@Test
public void testFunctionPrototypeNotWritableStrict() {
Object result = cx.evaluateString(
scope, " 'use strict';"
+ " function e() {}"
+ " e.__proto__ = true;"
+ " e.__proto__ != true;",
"test", 1, null
);
assertEquals(true, result);
}
}

Просмотреть файл

@ -0,0 +1,9 @@
package org.mozilla.javascript.tests.es6;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.drivers.LanguageVersion;
import org.mozilla.javascript.drivers.RhinoTest;
@RhinoTest("testsrc/jstests/es6/proto-property.js")
@LanguageVersion(Context.VERSION_ES6)
public class ProtoPropertyTest {}