зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1383630 - ScriptedProxyHandler should report which first property a TypeError is thrown for. r=jandem
This commit is contained in:
Родитель
f5a2166003
Коммит
8e8d3afeee
|
@ -402,29 +402,29 @@ MSG_DEF(JSMSG_PROXY_SETPROTOTYPEOF_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy setP
|
|||
MSG_DEF(JSMSG_PROXY_ISEXTENSIBLE_RETURNED_FALSE,0,JSEXN_TYPEERR,"proxy isExtensible handler must return the same extensibility as target")
|
||||
MSG_DEF(JSMSG_INCONSISTENT_SETPROTOTYPEOF_TRAP,0,JSEXN_TYPEERR,"proxy setPrototypeOf handler returned true, even though the target's prototype is immutable because the target is non-extensible")
|
||||
MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 0, JSEXN_TYPEERR, "can't change object's extensibility")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 0, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 0, JSEXN_TYPEERR, "proxy can't define a new property on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't define a non-existent property as non-configurable")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_INVALID, 2, JSEXN_TYPEERR, "proxy can't define an incompatible property descriptor ('{0}', {1})")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_NEW, 1, JSEXN_TYPEERR, "proxy can't define a new property '{0}' on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_DEFINE_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't define a non-existent '{0}' property as non-configurable")
|
||||
MSG_DEF(JSMSG_PROXY_DEFINE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy defineProperty handler returned false for property '{0}'")
|
||||
MSG_DEF(JSMSG_PROXY_DELETE_RETURNED_FALSE, 1, JSEXN_TYPEERR, "can't delete property '{0}': proxy deleteProperty handler returned false")
|
||||
MSG_DEF(JSMSG_PROXY_PREVENTEXTENSIONS_RETURNED_FALSE, 0, JSEXN_TYPEERR, "proxy preventExtensions handler returned false")
|
||||
MSG_DEF(JSMSG_PROXY_SET_RETURNED_FALSE, 1, JSEXN_TYPEERR, "proxy set handler returned false for property '{0}'")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_AS_NON_EXTENSIBLE, 0, JSEXN_TYPEERR, "proxy can't report an extensible object as non-extensible")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report existing configurable property as non-configurable")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NEW, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 0, JSEXN_TYPEERR, "proxy can't report a non-existent property as non-configurable")
|
||||
MSG_DEF(JSMSG_CANT_SET_NW_NC, 0, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property")
|
||||
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 0, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property without a setter")
|
||||
MSG_DEF(JSMSG_CANT_SKIP_NC, 0, JSEXN_TYPEERR, "proxy can't skip a non-configurable property")
|
||||
MSG_DEF(JSMSG_ONWKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements")
|
||||
MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 0, JSEXN_TYPEERR, "proxy must report the same value for a non-writable, non-configurable property")
|
||||
MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 0, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property without a getter")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_C_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report existing configurable property '{0}' as non-configurable")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report an existing own property '{0}' as non-existent on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_INVALID, 2, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor ('{0}', {1})")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE, 1, JSEXN_TYPEERR, "proxy can't report a non-configurable own property '{0}' as non-existent")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NEW, 1, JSEXN_TYPEERR, "proxy can't report a new property '{0}' on a non-extensible object")
|
||||
MSG_DEF(JSMSG_CANT_REPORT_NE_AS_NC, 1, JSEXN_TYPEERR, "proxy can't report a non-existent property '{0}' as non-configurable")
|
||||
MSG_DEF(JSMSG_CANT_SET_NW_NC, 1, JSEXN_TYPEERR, "proxy can't successfully set a non-writable, non-configurable property '{0}'")
|
||||
MSG_DEF(JSMSG_CANT_SET_WO_SETTER, 1, JSEXN_TYPEERR, "proxy can't succesfully set an accessor property '{0}' without a setter")
|
||||
MSG_DEF(JSMSG_CANT_SKIP_NC, 1, JSEXN_TYPEERR, "proxy can't skip a non-configurable property '{0}'")
|
||||
MSG_DEF(JSMSG_OWNKEYS_STR_SYM, 0, JSEXN_TYPEERR, "proxy [[OwnPropertyKeys]] must return an array with only string and symbol elements")
|
||||
MSG_DEF(JSMSG_MUST_REPORT_SAME_VALUE, 1, JSEXN_TYPEERR, "proxy must report the same value for the non-writable, non-configurable property '{0}'")
|
||||
MSG_DEF(JSMSG_MUST_REPORT_UNDEFINED, 1, JSEXN_TYPEERR, "proxy must report undefined for a non-configurable accessor property '{0}' without a getter")
|
||||
MSG_DEF(JSMSG_PROXY_CONSTRUCT_OBJECT, 0, JSEXN_TYPEERR, "proxy [[Construct]] must return an object")
|
||||
MSG_DEF(JSMSG_PROXY_EXTENSIBILITY, 0, JSEXN_TYPEERR, "proxy must report same extensiblitity as target")
|
||||
MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 0, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined")
|
||||
MSG_DEF(JSMSG_PROXY_GETOWN_OBJORUNDEF, 1, JSEXN_TYPEERR, "proxy [[GetOwnProperty]] must return an object or undefined for property '{0}'")
|
||||
MSG_DEF(JSMSG_PROXY_REVOKED, 0, JSEXN_TYPEERR, "illegal operation attempted on a revoked proxy")
|
||||
MSG_DEF(JSMSG_PROXY_ARG_REVOKED, 1, JSEXN_TYPEERR, "argument {0} cannot be a revoked proxy")
|
||||
MSG_DEF(JSMSG_BAD_TRAP, 1, JSEXN_TYPEERR, "proxy handler's {0} trap wasn't undefined, null, or callable")
|
||||
|
|
|
@ -250,9 +250,9 @@ GetPropertyIfPresent(JSContext* cx, HandleObject obj, HandleId id, MutableHandle
|
|||
}
|
||||
|
||||
bool
|
||||
js::Throw(JSContext* cx, jsid id, unsigned errorNumber)
|
||||
js::Throw(JSContext* cx, jsid id, unsigned errorNumber, const char* details)
|
||||
{
|
||||
MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == 1);
|
||||
MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == (details ? 2 : 1));
|
||||
|
||||
RootedValue idVal(cx, IdToValue(id));
|
||||
JSString* idstr = ValueToSource(cx, idVal);
|
||||
|
@ -261,7 +261,15 @@ js::Throw(JSContext* cx, jsid id, unsigned errorNumber)
|
|||
JSAutoByteString bytes(cx, idstr);
|
||||
if (!bytes)
|
||||
return false;
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr());
|
||||
|
||||
if (details) {
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr(),
|
||||
details);
|
||||
}
|
||||
else {
|
||||
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, errorNumber, bytes.ptr());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1391,7 +1391,7 @@ GetFirstArgumentAsObject(JSContext* cx, const CallArgs& args, const char* method
|
|||
|
||||
/* Helpers for throwing. These always return false. */
|
||||
extern bool
|
||||
Throw(JSContext* cx, jsid id, unsigned errorNumber);
|
||||
Throw(JSContext* cx, jsid id, unsigned errorNumber, const char* details = nullptr);
|
||||
|
||||
extern bool
|
||||
Throw(JSContext* cx, JSObject* obj, unsigned errorNumber);
|
||||
|
|
|
@ -23,14 +23,23 @@ using mozilla::ArrayLength;
|
|||
// 9.1.6.3 ValidateAndApplyPropertyDescriptor with two additional constant
|
||||
// arguments. Therefore step numbering is from the latter method, and
|
||||
// resulting dead code has been removed.
|
||||
|
||||
// If an exception should be thrown, we will set errorDetails.
|
||||
static bool
|
||||
IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDescriptor> desc,
|
||||
Handle<PropertyDescriptor> current, bool* bp)
|
||||
Handle<PropertyDescriptor> current, const char** errorDetails)
|
||||
{
|
||||
// precondition: we won't set details if checks pass, so it must be null here.
|
||||
MOZ_ASSERT(*errorDetails == nullptr);
|
||||
|
||||
// Step 2.
|
||||
if (!current.object()) {
|
||||
// Step 2a-b,e. As |O| is always undefined, steps 2c-d fall away.
|
||||
*bp = extensible;
|
||||
if (!extensible) {
|
||||
static const char* DETAILS_NOT_EXTENSIBLE =
|
||||
"proxy can't report an extensible object as non-extensible";
|
||||
*errorDetails = DETAILS_NOT_EXTENSIBLE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -39,7 +48,6 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDe
|
|||
!desc.hasGetterObject() && !desc.hasSetterObject() &&
|
||||
!desc.hasEnumerable() && !desc.hasConfigurable())
|
||||
{
|
||||
*bp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,44 +59,48 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDe
|
|||
(!desc.hasEnumerable() || desc.enumerable() == current.enumerable()) &&
|
||||
(!desc.hasConfigurable() || desc.configurable() == current.configurable()))
|
||||
{
|
||||
if (!desc.hasValue()) {
|
||||
*bp = true;
|
||||
if (!desc.hasValue())
|
||||
return true;
|
||||
}
|
||||
|
||||
bool same = false;
|
||||
if (!SameValue(cx, desc.value(), current.value(), &same))
|
||||
return false;
|
||||
if (same) {
|
||||
*bp = true;
|
||||
|
||||
if (same)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
if (!current.configurable()) {
|
||||
// Step 5a.
|
||||
if (desc.hasConfigurable() && desc.configurable()) {
|
||||
*bp = false;
|
||||
static const char* DETAILS_CANT_REPORT_NC_AS_C =
|
||||
"proxy can't report an existing non-configurable property as configurable";
|
||||
*errorDetails = DETAILS_CANT_REPORT_NC_AS_C;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 5b.
|
||||
if (desc.hasEnumerable() && desc.enumerable() != current.enumerable()) {
|
||||
*bp = false;
|
||||
static const char* DETAILS_ENUM_DIFFERENT =
|
||||
"proxy can't report a different 'enumerable' from target when target is not configurable";
|
||||
*errorDetails = DETAILS_ENUM_DIFFERENT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6.
|
||||
if (desc.isGenericDescriptor()) {
|
||||
*bp = true;
|
||||
if (desc.isGenericDescriptor())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 7.
|
||||
if (current.isDataDescriptor() != desc.isDataDescriptor()) {
|
||||
// Steps 7a, 11. As |O| is always undefined, steps 2b-c fall away.
|
||||
*bp = current.configurable();
|
||||
if (!current.configurable()) {
|
||||
static const char* DETAILS_CURRENT_NC_DIFF_TYPE =
|
||||
"proxy can't report a different descriptor type when target is not configurable";
|
||||
*errorDetails = DETAILS_CURRENT_NC_DIFF_TYPE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -97,7 +109,9 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDe
|
|||
MOZ_ASSERT(desc.isDataDescriptor()); // by step 7
|
||||
if (!current.configurable() && !current.writable()) {
|
||||
if (desc.hasWritable() && desc.writable()) {
|
||||
*bp = false;
|
||||
static const char* DETAILS_CANT_REPORT_NW_AS_W =
|
||||
"proxy can't report a non-configurable, non-writable property as writable";
|
||||
*errorDetails = DETAILS_CANT_REPORT_NW_AS_W;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -106,22 +120,33 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handle<PropertyDe
|
|||
if (!SameValue(cx, desc.value(), current.value(), &same))
|
||||
return false;
|
||||
if (!same) {
|
||||
*bp = false;
|
||||
static const char* DETAILS_DIFFERENT_VALUE =
|
||||
"proxy must report the same value for the non-writable, non-configurable property";
|
||||
*errorDetails = DETAILS_DIFFERENT_VALUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*bp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Step 9.
|
||||
MOZ_ASSERT(current.isAccessorDescriptor()); // by step 8
|
||||
MOZ_ASSERT(desc.isAccessorDescriptor()); // by step 7
|
||||
*bp = (current.configurable() ||
|
||||
((!desc.hasSetterObject() || desc.setter() == current.setter()) &&
|
||||
(!desc.hasGetterObject() || desc.getter() == current.getter())));
|
||||
|
||||
if (current.configurable())
|
||||
return true;
|
||||
if (desc.hasSetterObject() && (desc.setter() != current.setter())) {
|
||||
static const char* DETAILS_SETTERS_DIFFERENT =
|
||||
"proxy can't report different setters for a currently non-configurable property";
|
||||
*errorDetails = DETAILS_SETTERS_DIFFERENT;
|
||||
}
|
||||
else if (desc.hasGetterObject() && (desc.getter() != current.getter())) {
|
||||
static const char* DETAILS_GETTERS_DIFFERENT =
|
||||
"proxy can't report different getters for a currently non-configurable property";
|
||||
*errorDetails = DETAILS_GETTERS_DIFFERENT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -474,10 +499,8 @@ ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy
|
|||
return false;
|
||||
|
||||
// Step 9.
|
||||
if (!trapResult.isUndefined() && !trapResult.isObject()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_PROXY_GETOWN_OBJORUNDEF);
|
||||
return false;
|
||||
}
|
||||
if (!trapResult.isUndefined() && !trapResult.isObject())
|
||||
return js::Throw(cx, id, JSMSG_PROXY_GETOWN_OBJORUNDEF);
|
||||
|
||||
// Step 10.
|
||||
Rooted<PropertyDescriptor> targetDesc(cx);
|
||||
|
@ -493,10 +516,8 @@ ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy
|
|||
}
|
||||
|
||||
// Step 11b.
|
||||
if (!targetDesc.configurable()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NC_AS_NE);
|
||||
return false;
|
||||
}
|
||||
if (!targetDesc.configurable())
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_NC_AS_NE);
|
||||
|
||||
// Steps 11c-d.
|
||||
bool extensibleTarget;
|
||||
|
@ -504,10 +525,8 @@ ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy
|
|||
return false;
|
||||
|
||||
// Step 11e.
|
||||
if (!extensibleTarget) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_E_AS_NE);
|
||||
return false;
|
||||
}
|
||||
if (!extensibleTarget)
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_E_AS_NE);
|
||||
|
||||
// Step 11f.
|
||||
desc.object().set(nullptr);
|
||||
|
@ -528,27 +547,22 @@ ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy
|
|||
CompletePropertyDescriptor(&resultDesc);
|
||||
|
||||
// Step 15.
|
||||
bool valid;
|
||||
if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, resultDesc, targetDesc, &valid))
|
||||
const char* errorDetails = nullptr;
|
||||
if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, resultDesc, targetDesc,
|
||||
&errorDetails))
|
||||
return false;
|
||||
|
||||
// Step 16.
|
||||
if (!valid) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_INVALID);
|
||||
return false;
|
||||
}
|
||||
if (errorDetails)
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_INVALID, errorDetails);
|
||||
|
||||
// Step 17.
|
||||
if (!resultDesc.configurable()) {
|
||||
if (!targetDesc.object()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NE_AS_NC);
|
||||
return false;
|
||||
}
|
||||
if (!targetDesc.object())
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_NE_AS_NC);
|
||||
|
||||
if (targetDesc.configurable()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_C_AS_NC);
|
||||
return false;
|
||||
}
|
||||
if (targetDesc.configurable())
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_C_AS_NC);
|
||||
}
|
||||
|
||||
// Step 18.
|
||||
|
@ -625,25 +639,27 @@ ScriptedProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId
|
|||
// Steps 15-16.
|
||||
if (!targetDesc.object()) {
|
||||
// Step 15a.
|
||||
if (!extensibleTarget) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_NEW);
|
||||
return false;
|
||||
}
|
||||
if (!extensibleTarget)
|
||||
return js::Throw(cx, id, JSMSG_CANT_DEFINE_NEW);
|
||||
|
||||
// Step 15b.
|
||||
if (settingConfigFalse) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_NE_AS_NC);
|
||||
return false;
|
||||
}
|
||||
if (settingConfigFalse)
|
||||
return js::Throw(cx, id, JSMSG_CANT_DEFINE_NE_AS_NC);
|
||||
} else {
|
||||
// Steps 16a-b.
|
||||
bool valid;
|
||||
if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, desc, targetDesc, &valid))
|
||||
// Step 16a.
|
||||
const char* errorDetails = nullptr;
|
||||
if (!IsCompatiblePropertyDescriptor(cx, extensibleTarget, desc, targetDesc,
|
||||
&errorDetails))
|
||||
return false;
|
||||
|
||||
if (!valid || (settingConfigFalse && targetDesc.configurable())) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_DEFINE_INVALID);
|
||||
return false;
|
||||
if (errorDetails)
|
||||
return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, errorDetails);
|
||||
|
||||
// Step 16b.
|
||||
if (settingConfigFalse && targetDesc.configurable()) {
|
||||
static const char* DETAILS_CANT_REPORT_C_AS_NC =
|
||||
"proxy can't define an existing configurable property as non-configurable";
|
||||
return js::Throw(cx, id, JSMSG_CANT_DEFINE_INVALID, DETAILS_CANT_REPORT_C_AS_NC);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -677,7 +693,7 @@ CreateFilteredListFromArrayLike(JSContext* cx, HandleValue v, AutoIdVector& prop
|
|||
|
||||
// Step 6c.
|
||||
if (!next.isString() && !next.isSymbol()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ONWKEYS_STR_SYM);
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_OWNKEYS_STR_SYM);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -788,10 +804,8 @@ ScriptedProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdV
|
|||
auto ptr = uncheckedResultKeys.lookup(targetNonconfigurableKeys[i]);
|
||||
|
||||
// Step 17a.
|
||||
if (!ptr) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SKIP_NC);
|
||||
return false;
|
||||
}
|
||||
if (!ptr)
|
||||
return js::Throw(cx, targetNonconfigurableKeys[i], JSMSG_CANT_SKIP_NC);
|
||||
|
||||
// Step 17b.
|
||||
uncheckedResultKeys.remove(ptr);
|
||||
|
@ -808,20 +822,16 @@ ScriptedProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdV
|
|||
auto ptr = uncheckedResultKeys.lookup(targetConfigurableKeys[i]);
|
||||
|
||||
// Step 19a.
|
||||
if (!ptr) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_E_AS_NE);
|
||||
return false;
|
||||
}
|
||||
if (!ptr)
|
||||
return js::Throw(cx, targetConfigurableKeys[i], JSMSG_CANT_REPORT_E_AS_NE);
|
||||
|
||||
// Step 19b.
|
||||
uncheckedResultKeys.remove(ptr);
|
||||
}
|
||||
|
||||
// Step 20.
|
||||
if (!uncheckedResultKeys.empty()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NEW);
|
||||
return false;
|
||||
}
|
||||
if (!uncheckedResultKeys.empty())
|
||||
return js::Throw(cx, uncheckedResultKeys.all().front(), JSMSG_CANT_REPORT_NEW);
|
||||
|
||||
// Step 21.
|
||||
return props.appendAll(trapResult);
|
||||
|
@ -933,10 +943,8 @@ ScriptedProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool*
|
|||
// Step 9b.
|
||||
if (desc.object()) {
|
||||
// Step 9b(i).
|
||||
if (!desc.configurable()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_NC_AS_NE);
|
||||
return false;
|
||||
}
|
||||
if (!desc.configurable())
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_NC_AS_NE);
|
||||
|
||||
// Step 9b(ii).
|
||||
bool extensible;
|
||||
|
@ -944,10 +952,8 @@ ScriptedProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool*
|
|||
return false;
|
||||
|
||||
// Step 9b(iii).
|
||||
if (!extensible) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_REPORT_E_AS_NE);
|
||||
return false;
|
||||
}
|
||||
if (!extensible)
|
||||
return js::Throw(cx, id, JSMSG_CANT_REPORT_E_AS_NE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1011,18 +1017,17 @@ ScriptedProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receive
|
|||
bool same;
|
||||
if (!SameValue(cx, trapResult, desc.value(), &same))
|
||||
return false;
|
||||
if (!same) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MUST_REPORT_SAME_VALUE);
|
||||
return false;
|
||||
}
|
||||
if (!same)
|
||||
return js::Throw(cx, id, JSMSG_MUST_REPORT_SAME_VALUE);
|
||||
}
|
||||
|
||||
// Step 10b.
|
||||
if (desc.isAccessorDescriptor() && !desc.configurable() && desc.getterObject() == nullptr) {
|
||||
if (!trapResult.isUndefined()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MUST_REPORT_UNDEFINED);
|
||||
return false;
|
||||
}
|
||||
if (desc.isAccessorDescriptor() &&
|
||||
!desc.configurable() &&
|
||||
(desc.getterObject() == nullptr) &&
|
||||
!trapResult.isUndefined())
|
||||
{
|
||||
return js::Throw(cx, id, JSMSG_MUST_REPORT_UNDEFINED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1091,17 +1096,13 @@ ScriptedProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, Handle
|
|||
bool same;
|
||||
if (!SameValue(cx, v, desc.value(), &same))
|
||||
return false;
|
||||
if (!same) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_NW_NC);
|
||||
return false;
|
||||
}
|
||||
if (!same)
|
||||
return js::Throw(cx, id, JSMSG_CANT_SET_NW_NC);
|
||||
}
|
||||
|
||||
// Step 11b.
|
||||
if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_WO_SETTER);
|
||||
return false;
|
||||
}
|
||||
if (desc.isAccessorDescriptor() && !desc.configurable() && desc.setterObject() == nullptr)
|
||||
return js::Throw(cx, id, JSMSG_CANT_SET_WO_SETTER);
|
||||
}
|
||||
|
||||
// Step 12.
|
||||
|
|
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
/* These tests are not checking whether an exception is thrown or not for
|
||||
* proxies: those tests should already exist in js/src/tests/ecma_6/Proxy .
|
||||
* We expect TypeErrors to be thrown in these tests, with a stringification
|
||||
* of the error message showing whatever property name the error is being
|
||||
* reported for.
|
||||
*
|
||||
* Beyond the presence of the property name, these tests do not care about the
|
||||
* contents of the message.
|
||||
*
|
||||
* The reason for requiring the property name is simple: with ECMAScript
|
||||
* proxies, it can be really hard to figure out what little assertion causes a
|
||||
* TypeError in the first place.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
function assertThrowsTypeErrorIncludes(f, propStr, details) {
|
||||
var fullmsg;
|
||||
try {
|
||||
f();
|
||||
}
|
||||
catch (exc) {
|
||||
if (!(exc instanceof TypeError))
|
||||
fullmsg =
|
||||
"Assertion failed: expected TypeError, got " + exc;
|
||||
else if (!exc.message.includes(propStr))
|
||||
fullmsg =
|
||||
`Assertion failed: expected TypeError message '${exc.message}' to include '${propStr}'`;
|
||||
else if (details && !exc.message.includes(details))
|
||||
fullmsg =
|
||||
`Assertion failed: expected TypeError message '${exc.message}' to include '${details}'`;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (fullmsg === undefined) {
|
||||
fullmsg =
|
||||
"Assertion failed: expected TypeError, no exception thrown";
|
||||
}
|
||||
|
||||
throw new Error(fullmsg);
|
||||
}
|
||||
|
||||
const STR = "one", STR_NAME = `"one"`;
|
||||
const SYM = Symbol("two"), SYM_NAME = `'Symbol("two")'`;
|
||||
|
||||
function errorHasPropertyTests(test) {
|
||||
assertThrowsTypeErrorIncludes(() => test(STR), STR_NAME);
|
||||
assertThrowsTypeErrorIncludes(() => test(SYM), SYM_NAME);
|
||||
}
|
||||
|
||||
function errorHasPropertyTestsWithDetails(test) {
|
||||
let [throwable, details] = test(STR);
|
||||
assertThrowsTypeErrorIncludes(throwable, STR_NAME, details);
|
||||
|
||||
[throwable, details] = test(SYM);
|
||||
assertThrowsTypeErrorIncludes(throwable, SYM_NAME, details);
|
||||
}
|
||||
|
||||
// getOwnPropertyDescriptor
|
||||
|
||||
function testGetOwnPropertyDescriptor_OBJORUNDEF(propName) {
|
||||
// JSMSG_PROXY_GETOWN_OBJORUNDEF
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: () => 2
|
||||
};
|
||||
|
||||
const t = {};
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.getOwnPropertyDescriptor(p, propName);
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_NC_AS_NE(propName) {
|
||||
// JSMSG_CANT_REPORT_NC_AS_NE
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: () => undefined
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.getOwnPropertyDescriptor(p, propName);
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_E_AS_NE(propName) {
|
||||
// JSMSG_CANT_REPORT_E_AS_NE
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: () => undefined,
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Reflect.preventExtensions(t);
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.getOwnPropertyDescriptor(p, propName);
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_NE_AS_NC(propName) {
|
||||
// JSMSG_CANT_REPORT_NE_AS_NC
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.getOwnPropertyDescriptor(p, propName);
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_C_AS_NC(propName) {
|
||||
// JSMSG_CANT_REPORT_C_AS_NC
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false // here's the difference
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.getOwnPropertyDescriptor(p, propName);
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_NOT_EXTENSIBLE(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_NOT_EXTENSIBLE
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.preventExtensions(t);
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report an extensible object as non-extensible"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_C_AS_NC(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CANT_REPORT_NC_AS_C
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report an existing non-configurable property as configurable"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_ENUM_DIFFERENT_CURRENT(cEnumerable, propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_ENUM_DIFFERENT
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: !cEnumerable,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: cEnumerable,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report a different 'enumerable' from target when target is not configurable"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_CURRENT_NC_DIFF_TYPE(cAccessor, propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CURRENT_NC_DIFF_TYPE
|
||||
const accDesc = {
|
||||
get: () => 1,
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
};
|
||||
const dataDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: () => { return (cAccessor ? dataDesc : accDesc); }
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, cAccessor ? accDesc : dataDesc);
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report a different descriptor type when target is not configurable"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_NW_AS_W(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CANT_REPORT_NW_AS_W
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 2,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report a non-configurable, non-writable property as writable"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_DIFFERENT_VALUE(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_DIFFERENT_VALUE
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
value: 1,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 2,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy must report the same value for the non-writable, non-configurable property"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_SETTERS_DIFFERENT(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_SETTERS_DIFFERENT
|
||||
const g = () => 1;
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
get: g,
|
||||
set: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
get: g,
|
||||
set: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report different setters for a currently non-configurable property"];
|
||||
}
|
||||
|
||||
function testGetOwnPropertyDescriptor_INVALID_GETTERS_DIFFERENT(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_GETTERS_DIFFERENT
|
||||
const h = {
|
||||
getOwnPropertyDescriptor: function() {
|
||||
return {
|
||||
get: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
get: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.getOwnPropertyDescriptor(p, propName); },
|
||||
"proxy can't report different getters for a currently non-configurable property"];
|
||||
}
|
||||
|
||||
// defineProperty
|
||||
function testDefineProperty_CANT_DEFINE_NEW(propName) {
|
||||
// JSMSG_CANT_DEFINE_NEW
|
||||
const h = {
|
||||
defineProperty: () => true
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.preventExtensions(t);
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.defineProperty(p, propName, {});
|
||||
}
|
||||
|
||||
function testDefineProperty_NE_AS_NC(propName) {
|
||||
// JSMSG_CANT_DEFINE_NE_AS_NC
|
||||
const h = {
|
||||
defineProperty: () => true
|
||||
};
|
||||
|
||||
const t = {};
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.defineProperty(p, propName, {
|
||||
value: 1,
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
configurable: false,
|
||||
});
|
||||
}
|
||||
|
||||
/* Reflect.defineProperty(proxy, propName, desc) cannot throw
|
||||
* JSMSG_CANT_REPORT_INVALID with DETAILS_NOT_EXTENSIBLE. Here's why:
|
||||
*
|
||||
* To throw with DETAILS_NOT_EXTENSIBLE, current must be undefined and the
|
||||
* target must not be extensible, inside ValidateAndApplyPropertyDescriptor.
|
||||
*
|
||||
* ValidateAndApplyPropertyDescriptor's current is also
|
||||
* IsCompatiblePropertyDescriptor's current, and therefore also
|
||||
* targetDesc in [[DefineOwnProperty]] for proxies at step 16b.
|
||||
*
|
||||
* BUT step 16 is not reached if targetDesc in [[DefineOwnProperty]] is
|
||||
* undefined: instead step 15 is invoked. QED.
|
||||
*/
|
||||
|
||||
function testDefineProperty_INVALID_NC_AS_C(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CANT_REPORT_NC_AS_C
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't report an existing non-configurable property as configurable"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_ENUM_DIFFERENT_CURRENT(cEnumerable, propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_ENUM_DIFFERENT
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: !cEnumerable,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: cEnumerable,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't report a different 'enumerable' from target when target is not configurable"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_CURRENT_NC_DIFF_TYPE(cAccessor, propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CURRENT_NC_DIFF_TYPE
|
||||
const accDesc = {
|
||||
get: () => 1,
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
};
|
||||
const dataDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const h = {
|
||||
defineProperty: () => true,
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, cAccessor ? accDesc : dataDesc);
|
||||
const p = new Proxy(t, h);
|
||||
return [() => { Reflect.defineProperty(p, propName, cAccessor ? dataDesc : accDesc); },
|
||||
"proxy can't report a different descriptor type when target is not configurable"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_NW_AS_W(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_CANT_REPORT_NW_AS_W
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 2,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't report a non-configurable, non-writable property as writable"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_DIFFERENT_VALUE(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_DIFFERENT_VALUE
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
value: 1,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 2,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy must report the same value for the non-writable, non-configurable property"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_SETTERS_DIFFERENT(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_SETTERS_DIFFERENT
|
||||
const g = () => 1;
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
get: g,
|
||||
set: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
get: g,
|
||||
set: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't report different setters for a currently non-configurable property"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_GETTERS_DIFFERENT(propName) {
|
||||
// JSMSG_CANT_REPORT_INVALID, DETAILS_GETTERS_DIFFERENT
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
get: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
get: () => 2,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't report different getters for a currently non-configurable property"];
|
||||
}
|
||||
|
||||
function testDefineProperty_INVALID_C_AS_NC(propName) {
|
||||
const h = {
|
||||
defineProperty: function() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const newDesc = {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
return [() => { Reflect.defineProperty(p, propName, newDesc); },
|
||||
"proxy can't define an existing configurable property as non-configurable"];
|
||||
}
|
||||
|
||||
// ownKeys
|
||||
|
||||
function testOwnKeys_CANT_SKIP_NC(propName) {
|
||||
// JSMSG_CANT_SKIP_NC
|
||||
const h = {
|
||||
ownKeys: () => []
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.ownKeys(p);
|
||||
}
|
||||
|
||||
function testOwnKeys_E_AS_NE(propName) {
|
||||
// JSMSG_CANT_REPORT_E_AS_NE
|
||||
const h = {
|
||||
ownKeys: () => []
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
configurable: true,
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Reflect.preventExtensions(t);
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.ownKeys(p);
|
||||
}
|
||||
|
||||
// has
|
||||
|
||||
function testHas_NC_AS_NE(propName) {
|
||||
// JSMSG_CANT_REPORT_NC_AS_NE
|
||||
const h = {
|
||||
has: () => undefined
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.has(p, propName);
|
||||
}
|
||||
|
||||
function testHas_E_AS_NE(propName) {
|
||||
// JSMSG_CANT_REPORT_E_AS_NE
|
||||
const h = {
|
||||
has: () => undefined
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
Reflect.preventExtensions(t);
|
||||
const p = new Proxy(t, h);
|
||||
|
||||
Reflect.has(p, propName);
|
||||
}
|
||||
|
||||
// get
|
||||
|
||||
function testGet_SAME_VALUE(propName) {
|
||||
const h = {
|
||||
get: () => 2
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.get(p, propName);
|
||||
}
|
||||
|
||||
function testGet_MUST_REPORT_UNDEFINED(propName) {
|
||||
// JSMSG_MUST_REPORT_UNDEFINED
|
||||
const h = {
|
||||
get: () => 2
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
set: () => { /* do nothing */},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.get(p, propName);
|
||||
}
|
||||
|
||||
// set
|
||||
|
||||
function testSet_CANT_SET_NW_NC(propName) {
|
||||
// JSMSG_CANT_SET_NW_NC
|
||||
const h = {
|
||||
set: () => true,
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
value: 1,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.set(p, propName, 3);
|
||||
}
|
||||
|
||||
function testSet_WO_SETTER(propName) {
|
||||
// JSMSG_MUST_REPORT_UNDEFINED
|
||||
const h = {
|
||||
set: () => true
|
||||
};
|
||||
|
||||
const t = {};
|
||||
Reflect.defineProperty(t, propName, {
|
||||
get: () => { /* do nothing */},
|
||||
enumerable: true,
|
||||
configurable: false
|
||||
});
|
||||
|
||||
const p = new Proxy(t, h);
|
||||
Reflect.set(p, propName, 1);
|
||||
}
|
||||
|
||||
// test sequence
|
||||
|
||||
[
|
||||
testGetOwnPropertyDescriptor_OBJORUNDEF,
|
||||
testGetOwnPropertyDescriptor_NC_AS_NE,
|
||||
testGetOwnPropertyDescriptor_E_AS_NE,
|
||||
testGetOwnPropertyDescriptor_NE_AS_NC,
|
||||
testGetOwnPropertyDescriptor_C_AS_NC,
|
||||
|
||||
testDefineProperty_CANT_DEFINE_NEW,
|
||||
testDefineProperty_NE_AS_NC,
|
||||
|
||||
testOwnKeys_CANT_SKIP_NC,
|
||||
testOwnKeys_E_AS_NE,
|
||||
|
||||
testHas_NC_AS_NE,
|
||||
testHas_E_AS_NE,
|
||||
|
||||
testGet_SAME_VALUE,
|
||||
testGet_MUST_REPORT_UNDEFINED,
|
||||
|
||||
testSet_CANT_SET_NW_NC,
|
||||
testSet_WO_SETTER,
|
||||
].forEach(errorHasPropertyTests);
|
||||
|
||||
[
|
||||
testGetOwnPropertyDescriptor_INVALID_NOT_EXTENSIBLE,
|
||||
testGetOwnPropertyDescriptor_INVALID_C_AS_NC,
|
||||
testGetOwnPropertyDescriptor_INVALID_ENUM_DIFFERENT_CURRENT.bind(null, true),
|
||||
testGetOwnPropertyDescriptor_INVALID_ENUM_DIFFERENT_CURRENT.bind(null, false),
|
||||
testGetOwnPropertyDescriptor_INVALID_CURRENT_NC_DIFF_TYPE.bind(null, true),
|
||||
testGetOwnPropertyDescriptor_INVALID_CURRENT_NC_DIFF_TYPE.bind(null, false),
|
||||
testGetOwnPropertyDescriptor_INVALID_NW_AS_W,
|
||||
testGetOwnPropertyDescriptor_INVALID_DIFFERENT_VALUE,
|
||||
testGetOwnPropertyDescriptor_INVALID_SETTERS_DIFFERENT,
|
||||
testGetOwnPropertyDescriptor_INVALID_GETTERS_DIFFERENT,
|
||||
|
||||
testDefineProperty_INVALID_NC_AS_C,
|
||||
testDefineProperty_INVALID_ENUM_DIFFERENT_CURRENT.bind(null, true),
|
||||
testDefineProperty_INVALID_ENUM_DIFFERENT_CURRENT.bind(null, false),
|
||||
testDefineProperty_INVALID_CURRENT_NC_DIFF_TYPE.bind(null, true),
|
||||
testDefineProperty_INVALID_CURRENT_NC_DIFF_TYPE.bind(null, false),
|
||||
testDefineProperty_INVALID_NW_AS_W,
|
||||
testDefineProperty_INVALID_DIFFERENT_VALUE,
|
||||
testDefineProperty_INVALID_SETTERS_DIFFERENT,
|
||||
testDefineProperty_INVALID_GETTERS_DIFFERENT,
|
||||
testDefineProperty_INVALID_C_AS_NC,
|
||||
].forEach(errorHasPropertyTestsWithDetails);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
Загрузка…
Ссылка в новой задаче