зеркало из https://github.com/mozilla/rhino.git
re-formating with spotlessApply
This commit is contained in:
Родитель
1bfad4824b
Коммит
a736276482
|
@ -123,17 +123,21 @@ public class LambdaConstructor extends LambdaFunction {
|
|||
proto.defineProperty(key, value, attributes);
|
||||
}
|
||||
|
||||
public void definePrototypeProperty(String name, java.util.function.Function<Scriptable, Object> getter, int attributes) {
|
||||
public void definePrototypeProperty(
|
||||
String name, java.util.function.Function<Scriptable, Object> getter, int attributes) {
|
||||
ScriptableObject proto = getPrototypeScriptable();
|
||||
proto.defineProperty(name, getter, null, attributes);
|
||||
}
|
||||
|
||||
public void definePrototypeProperty(String name, Function<Scriptable, Object> getter, BiConsumer<Scriptable, Object> setter, int attributes) {
|
||||
public void definePrototypeProperty(
|
||||
String name,
|
||||
Function<Scriptable, Object> getter,
|
||||
BiConsumer<Scriptable, Object> setter,
|
||||
int attributes) {
|
||||
ScriptableObject proto = getPrototypeScriptable();
|
||||
proto.defineProperty(name, getter, setter, attributes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Define a function property directly on the constructor that is implemented under the covers
|
||||
* by a LambdaFunction.
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
package org.mozilla.javascript;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A specialized property accessor using lambda functions, similar to {@link LambdaSlot},
|
||||
* but allows defining properties with getter and setter lambdas that require access to the owner object ('this').
|
||||
* This enables the implementation of properties that can access instance fields of the owner.
|
||||
* A specialized property accessor using lambda functions, similar to {@link LambdaSlot}, but allows
|
||||
* defining properties with getter and setter lambdas that require access to the owner object
|
||||
* ('this'). This enables the implementation of properties that can access instance fields of the
|
||||
* owner.
|
||||
*
|
||||
* Unlike {@link LambdaSlot}, Lambda functions used to define getter and setter logic require the owner's
|
||||
* `Scriptable` object as one of the parameters.
|
||||
* This is particularly useful for implementing properties that behave like standard JavaScript properties,
|
||||
* but are implemented with native functionality without the need for reflection.
|
||||
* <p>Unlike {@link LambdaSlot}, Lambda functions used to define getter and setter logic require the
|
||||
* owner's `Scriptable` object as one of the parameters. This is particularly useful for
|
||||
* implementing properties that behave like standard JavaScript properties, but are implemented with
|
||||
* native functionality without the need for reflection.
|
||||
*/
|
||||
public class OwnerAwareLambdaSlot extends Slot {
|
||||
private transient Function<Scriptable, Object> getter;
|
||||
private transient BiConsumer<Scriptable, Object> setter;
|
||||
|
||||
OwnerAwareLambdaSlot(Object name, int index) {
|
||||
super(name, index, 0);
|
||||
}
|
||||
|
@ -30,23 +31,32 @@ public class OwnerAwareLambdaSlot extends Slot {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
ScriptableObject getPropertyDescriptor(Context cx, Scriptable scope) {
|
||||
ScriptableObject desc = (ScriptableObject) cx.newObject(scope);
|
||||
if (getter != null) {
|
||||
desc.defineProperty("get",
|
||||
new LambdaFunction(scope, "get " + super.name, 0, (cx1, scope1, thisObj, args) ->
|
||||
getter.apply(thisObj)), ScriptableObject.EMPTY);
|
||||
desc.defineProperty(
|
||||
"get",
|
||||
new LambdaFunction(
|
||||
scope,
|
||||
"get " + super.name,
|
||||
0,
|
||||
(cx1, scope1, thisObj, args) -> getter.apply(thisObj)),
|
||||
ScriptableObject.EMPTY);
|
||||
}
|
||||
|
||||
if (setter != null) {
|
||||
desc.defineProperty("set",
|
||||
new LambdaFunction(scope, "set " + super.name, 1, (cx1, scope1, thisObj, args) ->
|
||||
{
|
||||
desc.defineProperty(
|
||||
"set",
|
||||
new LambdaFunction(
|
||||
scope,
|
||||
"set " + super.name,
|
||||
1,
|
||||
(cx1, scope1, thisObj, args) -> {
|
||||
setter.accept(thisObj, args[0]);
|
||||
return Undefined.instance;
|
||||
}), ScriptableObject.EMPTY);
|
||||
}),
|
||||
ScriptableObject.EMPTY);
|
||||
}
|
||||
desc.setCommonDescriptorProperties(getAttributes(), false);
|
||||
return desc;
|
||||
|
|
|
@ -1692,28 +1692,34 @@ public abstract class ScriptableObject
|
|||
}
|
||||
|
||||
/**
|
||||
* Define a property on this object that is implemented using lambda functions accepting Scriptable `this` object
|
||||
* as first parameter. Unlike with `defineProperty(String name, Supplier<Object> getter, Consumer<Object> setter, int attributes)`
|
||||
* where getter and setter need to have access to target object instance, this allows for defining properties on
|
||||
* LambdaConstructor prototype providing getter and setter logic with java instance methods.
|
||||
* If a property with the same name already exists, then it will be replaced. This property will appear to the
|
||||
* JavaScript user exactly like any other property -- unlike Function properties and those based
|
||||
* on reflection, the property descriptor will only reflect the value as defined by this
|
||||
* function.
|
||||
* Define a property on this object that is implemented using lambda functions accepting
|
||||
* Scriptable `this` object as first parameter. Unlike with `defineProperty(String name,
|
||||
* Supplier<Object> getter, Consumer<Object> setter, int attributes)` where getter and setter
|
||||
* need to have access to target object instance, this allows for defining properties on
|
||||
* LambdaConstructor prototype providing getter and setter logic with java instance methods. If
|
||||
* a property with the same name already exists, then it will be replaced. This property will
|
||||
* appear to the JavaScript user exactly like any other property -- unlike Function properties
|
||||
* and those based on reflection, the property descriptor will only reflect the value as defined
|
||||
* by this function.
|
||||
*
|
||||
* @param name the name of the property
|
||||
* @param getter a function that given Scriptable `this` returns the value of the property. If null, throws typeError
|
||||
* @param setter a function that Scriptable `this` and a value sets the value of the property, by calling appropriate
|
||||
* method on `this`. If null, then the value will be
|
||||
* set directly and may not be retrieved by the getter.
|
||||
* @param getter a function that given Scriptable `this` returns the value of the property. If
|
||||
* null, throws typeError
|
||||
* @param setter a function that Scriptable `this` and a value sets the value of the property,
|
||||
* by calling appropriate method on `this`. If null, then the value will be set directly and
|
||||
* may not be retrieved by the getter.
|
||||
* @param attributes the attributes to set on the property
|
||||
*/
|
||||
public void defineProperty(
|
||||
String name, java.util.function.Function<Scriptable, Object> getter, BiConsumer<Scriptable, Object> setter, int attributes) {
|
||||
String name,
|
||||
java.util.function.Function<Scriptable, Object> getter,
|
||||
BiConsumer<Scriptable, Object> setter,
|
||||
int attributes) {
|
||||
if (getter == null && setter == null)
|
||||
throw ScriptRuntime.typeError("at least one of {getter, setter} is required");
|
||||
|
||||
OwnerAwareLambdaSlot slot = slotMap.compute(name, 0, ScriptableObject::ensureOwnerAwareLambdaSlot);
|
||||
OwnerAwareLambdaSlot slot =
|
||||
slotMap.compute(name, 0, ScriptableObject::ensureOwnerAwareLambdaSlot);
|
||||
slot.setAttributes(attributes);
|
||||
|
||||
slot.setGetter(getter);
|
||||
|
@ -2725,7 +2731,8 @@ public abstract class ScriptableObject
|
|||
}
|
||||
}
|
||||
|
||||
private static OwnerAwareLambdaSlot ensureOwnerAwareLambdaSlot(Object name, int index, Slot existing) {
|
||||
private static OwnerAwareLambdaSlot ensureOwnerAwareLambdaSlot(
|
||||
Object name, int index, Slot existing) {
|
||||
if (existing == null) {
|
||||
return new OwnerAwareLambdaSlot(name, index);
|
||||
} else if (existing instanceof OwnerAwareLambdaSlot) {
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
package org.mozilla.javascript.tests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
|
||||
import static org.mozilla.javascript.tests.OwnerAwareLambdaSlotTest.StatusHolder.self;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.ContextFactory;
|
||||
import org.mozilla.javascript.EcmaError;
|
||||
import org.mozilla.javascript.LambdaConstructor;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
import org.mozilla.javascript.ScriptableObject;
|
||||
import org.mozilla.javascript.Undefined;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mozilla.javascript.ScriptableObject.DONTENUM;
|
||||
import static org.mozilla.javascript.tests.OwnerAwareLambdaSlotTest.StatusHolder.self;
|
||||
|
||||
public class OwnerAwareLambdaSlotTest {
|
||||
private Context cx;
|
||||
private ScriptableObject scope;
|
||||
|
@ -30,45 +29,44 @@ public class OwnerAwareLambdaSlotTest {
|
|||
Context.exit();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetterProperty() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
(thisObj) -> self(thisObj).getStatus(),
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value),
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
|
||||
Object getterResult =
|
||||
cx.evaluateString(
|
||||
scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
|
||||
assertEquals("InProgress", getterResult);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThrowIfNeitherGetterOrSetterAreDefined() {
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
null,
|
||||
null,
|
||||
DONTENUM));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty("status", null, null, DONTENUM));
|
||||
assertTrue(error.toString().contains("at least one of {getter, setter} is required"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanUpdateValueUsingSetter() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
(thisObj) -> self(thisObj).getStatus(),
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value),
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
|
||||
Object getterResult =
|
||||
cx.evaluateString(
|
||||
scope, "s = new StatusHolder('InProgress'); s.status", "source", 1, null);
|
||||
assertEquals("InProgress", getterResult);
|
||||
|
||||
Object setResult = cx.evaluateString(scope, "s.status = 'DONE';", "source", 1, null);
|
||||
|
@ -79,45 +77,58 @@ public class OwnerAwareLambdaSlotTest {
|
|||
|
||||
@Test
|
||||
public void testOnlyGetterCanBeAccessed() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
|
||||
Object getterResult = cx.evaluateString(scope, "new StatusHolder('OK').status", "source", 1, null);
|
||||
Object getterResult =
|
||||
cx.evaluateString(scope, "new StatusHolder('OK').status", "source", 1, null);
|
||||
assertEquals("OK", getterResult);
|
||||
|
||||
Object hiddenFieldResult = cx.evaluateString(scope, "new StatusHolder('OK').hiddenStatus", "source", 1, null);
|
||||
assertEquals("fields not explicitly defined as properties should return undefined", Undefined.instance, hiddenFieldResult);
|
||||
Object hiddenFieldResult =
|
||||
cx.evaluateString(scope, "new StatusHolder('OK').hiddenStatus", "source", 1, null);
|
||||
assertEquals(
|
||||
"fields not explicitly defined as properties should return undefined",
|
||||
Undefined.instance,
|
||||
hiddenFieldResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenNoSetterDefined_InStrictMode_WillThrowException() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
(thisObj) -> self(thisObj).getStatus(),
|
||||
DONTENUM);
|
||||
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
Object getterResult =
|
||||
cx.evaluateString(
|
||||
scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
|
||||
assertEquals("Constant", getterResult);
|
||||
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
cx.evaluateString(scope,
|
||||
"\"use strict\"; s.status = 'DONE'; s.status", "source", 1, null));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"\"use strict\"; s.status = 'DONE'; s.status",
|
||||
"source",
|
||||
1,
|
||||
null));
|
||||
assertTrue(error.toString().contains("Cannot modify readonly property: status."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhenNoSetterDefined_InNormalMode_NoErrorButValueIsNotChanged() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
(thisObj) -> self(thisObj).getStatus(),
|
||||
DONTENUM);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
|
||||
Object getterResult = cx.evaluateString(scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
|
||||
Object getterResult =
|
||||
cx.evaluateString(
|
||||
scope, "s = new StatusHolder('Constant'); s.status", "source", 1, null);
|
||||
assertEquals("Constant", getterResult);
|
||||
|
||||
Object setResult = cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
|
||||
Object setResult =
|
||||
cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
|
||||
assertEquals("status won't be changed", "Constant", setResult);
|
||||
|
||||
Object shObj = cx.evaluateString(scope, "s", "source", 1, null);
|
||||
|
@ -127,18 +138,16 @@ public class OwnerAwareLambdaSlotTest {
|
|||
|
||||
@Test
|
||||
public void testSetterOnly_WillModifyUnderlyingValue() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
null,
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value),
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
cx.evaluateString(scope, "s = new StatusHolder('Constant')", "source", 1, null);
|
||||
|
||||
cx.evaluateString(scope, "s.status = 'DONE'; s.status", "source", 1, null);
|
||||
|
||||
|
||||
Object newStatus = cx.evaluateString(scope, "s.status", "source", 1, null);
|
||||
assertEquals(Undefined.instance, newStatus);
|
||||
Object shObj = cx.evaluateString(scope, "s", "source", 1, null);
|
||||
|
@ -146,147 +155,175 @@ public class OwnerAwareLambdaSlotTest {
|
|||
assertEquals("NewStatus: DONE", statusHolder.getStatus());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// using getOwnPropertyDescriptor to access property
|
||||
|
||||
@Test
|
||||
public void testGetterUsing_getOwnPropertyDescriptor() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
|
||||
Object result = cx.evaluateString(scope, "s = new StatusHolder('InProgress');" +
|
||||
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.get.call(s)",
|
||||
"source", 1, null);
|
||||
Object result =
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"s = new StatusHolder('InProgress');"
|
||||
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.get.call(s)",
|
||||
"source",
|
||||
1,
|
||||
null);
|
||||
assertEquals("InProgress", result);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetterOnlyUsing_getOwnPropertyDescriptor() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
null,
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value), DONTENUM);
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
Object shObj = cx.evaluateString(scope,
|
||||
"s = new StatusHolder('InProgress');" +
|
||||
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.set.call(s, 'DONE');" +
|
||||
"s",
|
||||
"source", 1, null);
|
||||
Object shObj =
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"s = new StatusHolder('InProgress');"
|
||||
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.set.call(s, 'DONE');"
|
||||
+ "s",
|
||||
"source",
|
||||
1,
|
||||
null);
|
||||
var statusHolder = (StatusHolder) shObj;
|
||||
assertEquals("NewStatus: DONE", statusHolder.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetValueUsing_getOwnPropertyDescriptor() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
(thisObj) -> self(thisObj).getStatus(),
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value), DONTENUM);
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
Object result = cx.evaluateString(scope,
|
||||
"s = new StatusHolder('InProgress');" +
|
||||
"f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.set.call(s, 'DONE');" +
|
||||
"s.status",
|
||||
"source", 1, null);
|
||||
Object result =
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"s = new StatusHolder('InProgress');"
|
||||
+ "f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.set.call(s, 'DONE');"
|
||||
+ "s.status",
|
||||
"source",
|
||||
1,
|
||||
null);
|
||||
assertEquals("Status with prefix", "NewStatus: DONE", result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetterOnlyUsing_getOwnPropertyDescriptor_ErrorOnGet() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
null,
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value), DONTENUM);
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
cx.evaluateString(scope,
|
||||
"var s = new StatusHolder('InProgress');" +
|
||||
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.get.call(s)",
|
||||
"source", 1, null));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"var s = new StatusHolder('InProgress');"
|
||||
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.get.call(s)",
|
||||
"source",
|
||||
1,
|
||||
null));
|
||||
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetterOnlyUsing_getOwnPropertyDescriptor_InStrictMode_ErrorOnGet() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status",
|
||||
null,
|
||||
(thisObj, value) ->
|
||||
self(thisObj).setStatus(value), DONTENUM);
|
||||
(thisObj, value) -> self(thisObj).setStatus(value),
|
||||
DONTENUM);
|
||||
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
cx.evaluateString(scope,
|
||||
"\"use strict\";"+
|
||||
"var s = new StatusHolder('InProgress');" +
|
||||
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.get.call(s)",
|
||||
"source", 1, null));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"\"use strict\";"
|
||||
+ "var s = new StatusHolder('InProgress');"
|
||||
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.get.call(s)",
|
||||
"source",
|
||||
1,
|
||||
null));
|
||||
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetterOnlyUsing_getOwnPropertyDescriptor_ErrorOnSet() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
|
||||
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
cx.evaluateString(scope,
|
||||
"var s = new StatusHolder('InProgress');" +
|
||||
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.set.call(s, 'DONE');" +
|
||||
"s.status",
|
||||
"source", 1, null));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"var s = new StatusHolder('InProgress');"
|
||||
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.set.call(s, 'DONE');"
|
||||
+ "s.status",
|
||||
"source",
|
||||
1,
|
||||
null));
|
||||
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetterOnlyUsing_getOwnPropertyDescriptor_InStrictMode_ErrorOnSet() {
|
||||
StatusHolder
|
||||
.init(scope)
|
||||
.definePrototypeProperty("status",
|
||||
(thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
StatusHolder.init(scope)
|
||||
.definePrototypeProperty(
|
||||
"status", (thisObj) -> self(thisObj).getStatus(), DONTENUM);
|
||||
|
||||
|
||||
var error = assertThrows(EcmaError.class, () ->
|
||||
cx.evaluateString(scope,
|
||||
"\"use strict\";" +
|
||||
"var s = new StatusHolder('InProgress');" +
|
||||
"var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');" +
|
||||
"f.set.call(s, 'DONE');" +
|
||||
"s.status",
|
||||
"source", 1, null));
|
||||
var error =
|
||||
assertThrows(
|
||||
EcmaError.class,
|
||||
() ->
|
||||
cx.evaluateString(
|
||||
scope,
|
||||
"\"use strict\";"
|
||||
+ "var s = new StatusHolder('InProgress');"
|
||||
+ "var f = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(s), 'status');"
|
||||
+ "f.set.call(s, 'DONE');"
|
||||
+ "s.status",
|
||||
"source",
|
||||
1,
|
||||
null));
|
||||
assertTrue(error.toString().contains("Cannot call method \"call\" of undefined"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static class StatusHolder extends ScriptableObject {
|
||||
private String status;
|
||||
private final String hiddenStatus;
|
||||
|
||||
static LambdaConstructor init(Scriptable scope) {
|
||||
LambdaConstructor constructor = new LambdaConstructor(scope, "StatusHolder", 1,
|
||||
LambdaConstructor constructor =
|
||||
new LambdaConstructor(
|
||||
scope,
|
||||
"StatusHolder",
|
||||
1,
|
||||
LambdaConstructor.CONSTRUCTOR_NEW,
|
||||
(cx, scope1, args) -> new StatusHolder((String) args[0]));
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче