зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1332713 part 4. Make Promise-returning getters return a rejected Promise on exception instead of throwing. r=qdot
This commit is contained in:
Родитель
ecfa536932
Коммит
39d50c2647
|
@ -2855,6 +2855,50 @@ GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||||
|
{
|
||||||
|
// Make sure to save the callee before someone maybe messes with rval().
|
||||||
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||||
|
JS::Rooted<JSObject*> callee(cx, &args.callee());
|
||||||
|
|
||||||
|
// We could invoke GenericBindingGetter here, but that involves an
|
||||||
|
// extra call. Manually inline it instead.
|
||||||
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
||||||
|
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
|
||||||
|
if (!args.thisv().isObject()) {
|
||||||
|
ThrowInvalidThis(cx, args, false, protoID);
|
||||||
|
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||||
|
args.rval());
|
||||||
|
}
|
||||||
|
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
|
||||||
|
|
||||||
|
void* self;
|
||||||
|
{
|
||||||
|
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
ThrowInvalidThis(cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO,
|
||||||
|
protoID);
|
||||||
|
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||||
|
args.rval());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(info->type() == JSJitInfo::Getter);
|
||||||
|
JSJitGetterOp getter = info->getter;
|
||||||
|
bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
|
||||||
|
if (ok) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
AssertReturnTypeMatchesJitinfo(info, args.rval());
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Promise-returning getters always return objects
|
||||||
|
MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
|
||||||
|
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||||
|
args.rval());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2997,6 +2997,9 @@ class PinnedStringId
|
||||||
bool
|
bool
|
||||||
GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
|
bool
|
||||||
|
GenericPromiseReturningBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
|
|
|
@ -2652,15 +2652,38 @@ class AttrDefiner(PropertyDefiner):
|
||||||
|
|
||||||
def getter(attr):
|
def getter(attr):
|
||||||
if self.static:
|
if self.static:
|
||||||
|
if attr.type.isPromise():
|
||||||
|
raise TypeError("Don't know how to handle "
|
||||||
|
"static Promise-returning "
|
||||||
|
"attribute %s.%s" %
|
||||||
|
(self.descriptor.name,
|
||||||
|
attr.identifier.name))
|
||||||
accessor = 'get_' + IDLToCIdentifier(attr.identifier.name)
|
accessor = 'get_' + IDLToCIdentifier(attr.identifier.name)
|
||||||
jitinfo = "nullptr"
|
jitinfo = "nullptr"
|
||||||
else:
|
else:
|
||||||
if attr.hasLenientThis():
|
if attr.hasLenientThis():
|
||||||
|
if attr.type.isPromise():
|
||||||
|
raise TypeError("Don't know how to handle "
|
||||||
|
"[LenientThis] Promise-returning "
|
||||||
|
"attribute %s.%s" %
|
||||||
|
(self.descriptor.name,
|
||||||
|
attr.identifier.name))
|
||||||
accessor = "genericLenientGetter"
|
accessor = "genericLenientGetter"
|
||||||
elif attr.getExtendedAttribute("CrossOriginReadable"):
|
elif attr.getExtendedAttribute("CrossOriginReadable"):
|
||||||
|
if attr.type.isPromise():
|
||||||
|
raise TypeError("Don't know how to handle "
|
||||||
|
"cross-origin Promise-returning "
|
||||||
|
"attribute %s.%s" %
|
||||||
|
(self.descriptor.name,
|
||||||
|
attr.identifier.name))
|
||||||
accessor = "genericCrossOriginGetter"
|
accessor = "genericCrossOriginGetter"
|
||||||
elif self.descriptor.needsSpecialGenericOps():
|
elif self.descriptor.needsSpecialGenericOps():
|
||||||
accessor = "genericGetter"
|
if attr.type.isPromise():
|
||||||
|
accessor = "genericPromiseReturningGetter"
|
||||||
|
else:
|
||||||
|
accessor = "genericGetter"
|
||||||
|
elif attr.type.isPromise():
|
||||||
|
accessor = "GenericPromiseReturningBindingGetter"
|
||||||
else:
|
else:
|
||||||
accessor = "GenericBindingGetter"
|
accessor = "GenericBindingGetter"
|
||||||
jitinfo = ("&%s_getterinfo" %
|
jitinfo = ("&%s_getterinfo" %
|
||||||
|
@ -8831,6 +8854,53 @@ class CGGenericGetter(CGAbstractBindingMethod):
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
|
|
||||||
|
class CGGenericPromiseReturningGetter(CGAbstractBindingMethod):
|
||||||
|
"""
|
||||||
|
A class for generating the C++ code for an IDL getter that returns a Promise.
|
||||||
|
|
||||||
|
Does not handle cross-origin this or [LenientThis].
|
||||||
|
"""
|
||||||
|
def __init__(self, descriptor):
|
||||||
|
unwrapFailureCode = fill(
|
||||||
|
"""
|
||||||
|
ThrowInvalidThis(cx, args, %%(securityError)s, "${iface}");
|
||||||
|
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||||
|
args.rval());
|
||||||
|
""",
|
||||||
|
iface=descriptor.interface.identifier.name)
|
||||||
|
name = "genericPromiseReturningGetter"
|
||||||
|
customCallArgs = dedent(
|
||||||
|
"""
|
||||||
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||||
|
// Make sure to save the callee before someone maybe messes with rval().
|
||||||
|
JS::Rooted<JSObject*> callee(cx, &args.callee());
|
||||||
|
""")
|
||||||
|
|
||||||
|
CGAbstractBindingMethod.__init__(self, descriptor, name,
|
||||||
|
JSNativeArguments(),
|
||||||
|
callArgs=customCallArgs,
|
||||||
|
unwrapFailureCode=unwrapFailureCode)
|
||||||
|
|
||||||
|
def generate_code(self):
|
||||||
|
return CGGeneric(dedent(
|
||||||
|
"""
|
||||||
|
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
|
||||||
|
MOZ_ASSERT(info->type() == JSJitInfo::Getter);
|
||||||
|
JSJitGetterOp getter = info->getter;
|
||||||
|
bool ok = getter(cx, obj, self, JSJitGetterCallArgs(args));
|
||||||
|
if (ok) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
AssertReturnTypeMatchesJitinfo(info, args.rval());
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(info->returnType() == JSVAL_TYPE_OBJECT);
|
||||||
|
return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee),
|
||||||
|
args.rval());
|
||||||
|
"""))
|
||||||
|
|
||||||
|
|
||||||
class CGSpecializedGetter(CGAbstractStaticMethod):
|
class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||||
"""
|
"""
|
||||||
A class for generating the code for a specialized attribute getter
|
A class for generating the code for a specialized attribute getter
|
||||||
|
@ -8946,6 +9016,41 @@ class CGSpecializedGetter(CGAbstractStaticMethod):
|
||||||
return nativeName
|
return nativeName
|
||||||
|
|
||||||
|
|
||||||
|
class CGGetterPromiseWrapper(CGAbstractStaticMethod):
|
||||||
|
"""
|
||||||
|
A class for generating a wrapper around another getter that will
|
||||||
|
convert exceptions to promises.
|
||||||
|
"""
|
||||||
|
def __init__(self, descriptor, getterToWrap):
|
||||||
|
self.getter = getterToWrap
|
||||||
|
name = self.makeName(getterToWrap.name)
|
||||||
|
args = list(getterToWrap.args)
|
||||||
|
CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
|
||||||
|
|
||||||
|
def definition_body(self):
|
||||||
|
return fill(
|
||||||
|
"""
|
||||||
|
bool ok = ${getterName}(${args});
|
||||||
|
if (ok) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
JS::Rooted<JSObject*> globalForPromise(cx);
|
||||||
|
// We can't use xpc::XrayAwareCalleeGlobal here because we have no
|
||||||
|
// callee. Use our hacky version instead.
|
||||||
|
if (!xpc::XrayAwareCalleeGlobalForSpecializedGetters(cx, obj,
|
||||||
|
&globalForPromise)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ConvertExceptionToPromise(cx, globalForPromise, args.rval());
|
||||||
|
""",
|
||||||
|
getterName=self.getter.name,
|
||||||
|
args=", ".join(arg.name for arg in self.args))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def makeName(getterName):
|
||||||
|
return getterName + "_promiseWrapper"
|
||||||
|
|
||||||
|
|
||||||
class CGStaticGetter(CGAbstractStaticBindingMethod):
|
class CGStaticGetter(CGAbstractStaticBindingMethod):
|
||||||
"""
|
"""
|
||||||
A class for generating the C++ code for an IDL static attribute getter.
|
A class for generating the C++ code for an IDL static attribute getter.
|
||||||
|
@ -9237,8 +9342,10 @@ class CGMemberJITInfo(CGThing):
|
||||||
IDLToCIdentifier(self.member.identifier.name))
|
IDLToCIdentifier(self.member.identifier.name))
|
||||||
# We need the cast here because JSJitGetterOp has a "void* self"
|
# We need the cast here because JSJitGetterOp has a "void* self"
|
||||||
# while we have the right type.
|
# while we have the right type.
|
||||||
getter = ("(JSJitGetterOp)get_%s" %
|
name = IDLToCIdentifier(self.member.identifier.name)
|
||||||
IDLToCIdentifier(self.member.identifier.name))
|
if self.member.type.isPromise():
|
||||||
|
name = CGGetterPromiseWrapper.makeName(name)
|
||||||
|
getter = ("(JSJitGetterOp)get_%s" % name)
|
||||||
extendedAttrs = self.descriptor.getExtendedAttributes(self.member, getter=True)
|
extendedAttrs = self.descriptor.getExtendedAttributes(self.member, getter=True)
|
||||||
getterinfal = "infallible" in extendedAttrs
|
getterinfal = "infallible" in extendedAttrs
|
||||||
|
|
||||||
|
@ -12192,6 +12299,7 @@ class MemberProperties:
|
||||||
self.isGenericGetter = False
|
self.isGenericGetter = False
|
||||||
self.isLenientGetter = False
|
self.isLenientGetter = False
|
||||||
self.isCrossOriginGetter = False
|
self.isCrossOriginGetter = False
|
||||||
|
self.isPromiseReturningGetter = False
|
||||||
self.isGenericSetter = False
|
self.isGenericSetter = False
|
||||||
self.isLenientSetter = False
|
self.isLenientSetter = False
|
||||||
self.isCrossOriginSetter = False
|
self.isCrossOriginSetter = False
|
||||||
|
@ -12220,7 +12328,10 @@ def memberProperties(m, descriptor):
|
||||||
elif m.getExtendedAttribute("CrossOriginReadable"):
|
elif m.getExtendedAttribute("CrossOriginReadable"):
|
||||||
props.isCrossOriginGetter = True
|
props.isCrossOriginGetter = True
|
||||||
elif descriptor.needsSpecialGenericOps():
|
elif descriptor.needsSpecialGenericOps():
|
||||||
props.isGenericGetter = True
|
if m.type.isPromise():
|
||||||
|
props.isPromiseReturningGetter = True
|
||||||
|
else:
|
||||||
|
props.isGenericGetter = True
|
||||||
if not m.readonly:
|
if not m.readonly:
|
||||||
if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
|
if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
|
||||||
if m.hasLenientThis():
|
if m.hasLenientThis():
|
||||||
|
@ -12262,7 +12373,8 @@ class CGDescriptor(CGThing):
|
||||||
# These are set to true if at least one non-static
|
# These are set to true if at least one non-static
|
||||||
# method/getter/setter or jsonifier exist on the interface.
|
# method/getter/setter or jsonifier exist on the interface.
|
||||||
(hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
|
(hasMethod, hasGetter, hasLenientGetter, hasSetter, hasLenientSetter,
|
||||||
hasPromiseReturningMethod) = False, False, False, False, False, False
|
hasPromiseReturningMethod, hasPromiseReturningGetter) = (
|
||||||
|
False, False, False, False, False, False, False)
|
||||||
jsonifierMethod = None
|
jsonifierMethod = None
|
||||||
crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set()
|
crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set()
|
||||||
unscopableNames = list()
|
unscopableNames = list()
|
||||||
|
@ -12313,7 +12425,10 @@ class CGDescriptor(CGThing):
|
||||||
elif descriptor.interface.hasInterfacePrototypeObject():
|
elif descriptor.interface.hasInterfacePrototypeObject():
|
||||||
if isNonExposedNavigatorObjectGetter(m, descriptor):
|
if isNonExposedNavigatorObjectGetter(m, descriptor):
|
||||||
continue
|
continue
|
||||||
cgThings.append(CGSpecializedGetter(descriptor, m))
|
specializedGetter = CGSpecializedGetter(descriptor, m)
|
||||||
|
cgThings.append(specializedGetter)
|
||||||
|
if m.type.isPromise():
|
||||||
|
cgThings.append(CGGetterPromiseWrapper(descriptor, specializedGetter))
|
||||||
if props.isCrossOriginGetter:
|
if props.isCrossOriginGetter:
|
||||||
crossOriginGetters.add(m.identifier.name)
|
crossOriginGetters.add(m.identifier.name)
|
||||||
if not m.readonly:
|
if not m.readonly:
|
||||||
|
@ -12339,6 +12454,8 @@ class CGDescriptor(CGThing):
|
||||||
hasMethod = hasMethod or props.isGenericMethod
|
hasMethod = hasMethod or props.isGenericMethod
|
||||||
hasPromiseReturningMethod = (hasPromiseReturningMethod or
|
hasPromiseReturningMethod = (hasPromiseReturningMethod or
|
||||||
props.isPromiseReturningMethod)
|
props.isPromiseReturningMethod)
|
||||||
|
hasPromiseReturningGetter = (hasPromiseReturningGetter or
|
||||||
|
props.isPromiseReturningGetter)
|
||||||
hasGetter = hasGetter or props.isGenericGetter
|
hasGetter = hasGetter or props.isGenericGetter
|
||||||
hasLenientGetter = hasLenientGetter or props.isLenientGetter
|
hasLenientGetter = hasLenientGetter or props.isLenientGetter
|
||||||
hasSetter = hasSetter or props.isGenericSetter
|
hasSetter = hasSetter or props.isGenericSetter
|
||||||
|
@ -12357,6 +12474,8 @@ class CGDescriptor(CGThing):
|
||||||
allowCrossOriginThis=True))
|
allowCrossOriginThis=True))
|
||||||
if hasGetter:
|
if hasGetter:
|
||||||
cgThings.append(CGGenericGetter(descriptor))
|
cgThings.append(CGGenericGetter(descriptor))
|
||||||
|
if hasPromiseReturningGetter:
|
||||||
|
cgThings.append(CGGenericPromiseReturningGetter(descriptor))
|
||||||
if hasLenientGetter:
|
if hasLenientGetter:
|
||||||
cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
|
cgThings.append(CGGenericGetter(descriptor, lenientThis=True))
|
||||||
if len(crossOriginGetters):
|
if len(crossOriginGetters):
|
||||||
|
|
|
@ -1117,10 +1117,12 @@ IdlInterface.prototype.test_member_const = function(member)
|
||||||
//@}
|
//@}
|
||||||
IdlInterface.prototype.test_member_attribute = function(member)
|
IdlInterface.prototype.test_member_attribute = function(member)
|
||||||
//@{
|
//@{
|
||||||
{
|
{
|
||||||
test(function()
|
var a_test = async_test(this.name + " interface: attribute " + member.name);
|
||||||
|
a_test.step(function()
|
||||||
{
|
{
|
||||||
if (this.is_callback() && !this.has_constants()) {
|
if (this.is_callback() && !this.has_constants()) {
|
||||||
|
a_test.done()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,6 +1135,7 @@ IdlInterface.prototype.test_member_attribute = function(member)
|
||||||
assert_own_property(self[this.name], member.name,
|
assert_own_property(self[this.name], member.name,
|
||||||
"The interface object must have a property " +
|
"The interface object must have a property " +
|
||||||
format_value(member.name));
|
format_value(member.name));
|
||||||
|
a_test.done();
|
||||||
} else if (this.is_global()) {
|
} else if (this.is_global()) {
|
||||||
assert_own_property(self, member.name,
|
assert_own_property(self, member.name,
|
||||||
"The global object must have a property " +
|
"The global object must have a property " +
|
||||||
|
@ -1161,23 +1164,42 @@ IdlInterface.prototype.test_member_attribute = function(member)
|
||||||
"Gets on a global should not require an explicit this");
|
"Gets on a global should not require an explicit this");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.do_interface_attribute_asserts(self, member);
|
// do_interface_attribute_asserts must be the last thing we do,
|
||||||
|
// since it will call done() on a_test.
|
||||||
|
this.do_interface_attribute_asserts(self, member, a_test);
|
||||||
} else {
|
} else {
|
||||||
assert_true(member.name in self[this.name].prototype,
|
assert_true(member.name in self[this.name].prototype,
|
||||||
"The prototype object must have a property " +
|
"The prototype object must have a property " +
|
||||||
format_value(member.name));
|
format_value(member.name));
|
||||||
|
|
||||||
if (!member.has_extended_attribute("LenientThis")) {
|
if (!member.has_extended_attribute("LenientThis")) {
|
||||||
assert_throws(new TypeError(), function() {
|
if (member.idlType.generic !== "Promise") {
|
||||||
self[this.name].prototype[member.name];
|
assert_throws(new TypeError(), function() {
|
||||||
}.bind(this), "getting property on prototype object must throw TypeError");
|
self[this.name].prototype[member.name];
|
||||||
|
}.bind(this), "getting property on prototype object must throw TypeError");
|
||||||
|
// do_interface_attribute_asserts must be the last thing we
|
||||||
|
// do, since it will call done() on a_test.
|
||||||
|
this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
|
||||||
|
} else {
|
||||||
|
promise_rejects(a_test, new TypeError(),
|
||||||
|
self[this.name].prototype[member.name])
|
||||||
|
.then(function() {
|
||||||
|
// do_interface_attribute_asserts must be the last
|
||||||
|
// thing we do, since it will call done() on a_test.
|
||||||
|
this.do_interface_attribute_asserts(self[this.name].prototype,
|
||||||
|
member, a_test);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert_equals(self[this.name].prototype[member.name], undefined,
|
assert_equals(self[this.name].prototype[member.name], undefined,
|
||||||
"getting property on prototype object must return undefined");
|
"getting property on prototype object must return undefined");
|
||||||
|
// do_interface_attribute_asserts must be the last thing we do,
|
||||||
|
// since it will call done() on a_test.
|
||||||
|
this.do_interface_attribute_asserts(self[this.name].prototype, member, a_test);
|
||||||
}
|
}
|
||||||
this.do_interface_attribute_asserts(self[this.name].prototype, member);
|
|
||||||
}
|
}
|
||||||
}.bind(this), this.name + " interface: attribute " + member.name);
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
@ -1522,12 +1544,13 @@ IdlInterface.prototype.test_interface_of = function(desc, obj, exception, expect
|
||||||
var member = this.members[i];
|
var member = this.members[i];
|
||||||
if (member.type == "attribute" && member.isUnforgeable)
|
if (member.type == "attribute" && member.isUnforgeable)
|
||||||
{
|
{
|
||||||
test(function()
|
var a_test = async_test(this.name + " interface: " + desc + ' must have own property "' + member.name + '"');
|
||||||
{
|
a_test.step(function() {
|
||||||
assert_equals(exception, null, "Unexpected exception when evaluating object");
|
assert_equals(exception, null, "Unexpected exception when evaluating object");
|
||||||
assert_equals(typeof obj, expected_typeof, "wrong typeof object");
|
assert_equals(typeof obj, expected_typeof, "wrong typeof object");
|
||||||
this.do_interface_attribute_asserts(obj, member);
|
// Call do_interface_attribute_asserts last, since it will call a_test.done()
|
||||||
}.bind(this), this.name + " interface: " + desc + ' must have own property "' + member.name + '"');
|
this.do_interface_attribute_asserts(obj, member, a_test);
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
else if (member.type == "operation" &&
|
else if (member.type == "operation" &&
|
||||||
member.name &&
|
member.name &&
|
||||||
|
@ -1646,7 +1669,7 @@ IdlInterface.prototype.has_stringifier = function()
|
||||||
};
|
};
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member)
|
IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member, a_test)
|
||||||
//@{
|
//@{
|
||||||
{
|
{
|
||||||
// This function tests WebIDL as of 2015-01-27.
|
// This function tests WebIDL as of 2015-01-27.
|
||||||
|
@ -1656,6 +1679,8 @@ IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member)
|
||||||
// it is not a global, and the global otherwise, and by test_interface_of()
|
// it is not a global, and the global otherwise, and by test_interface_of()
|
||||||
// with the object as obj.
|
// with the object as obj.
|
||||||
|
|
||||||
|
var pendingPromises = [];
|
||||||
|
|
||||||
// "For each exposed attribute of the interface, whether it was declared on
|
// "For each exposed attribute of the interface, whether it was declared on
|
||||||
// the interface itself or one of its consequential interfaces, there MUST
|
// the interface itself or one of its consequential interfaces, there MUST
|
||||||
// exist a corresponding property. The characteristics of this property are
|
// exist a corresponding property. The characteristics of this property are
|
||||||
|
@ -1695,9 +1720,15 @@ IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member)
|
||||||
// attribute, then return undefined.
|
// attribute, then return undefined.
|
||||||
// "Otherwise, throw a TypeError."
|
// "Otherwise, throw a TypeError."
|
||||||
if (!member.has_extended_attribute("LenientThis")) {
|
if (!member.has_extended_attribute("LenientThis")) {
|
||||||
assert_throws(new TypeError(), function() {
|
if (member.idlType.generic !== "Promise") {
|
||||||
desc.get.call({});
|
assert_throws(new TypeError(), function() {
|
||||||
}.bind(this), "calling getter on wrong object type must throw TypeError");
|
desc.get.call({});
|
||||||
|
}.bind(this), "calling getter on wrong object type must throw TypeError");
|
||||||
|
} else {
|
||||||
|
pendingPromises.push(
|
||||||
|
promise_rejects(a_test, new TypeError(), desc.get.call({}),
|
||||||
|
"calling getter on wrong object type must reject the return promise with TypeError"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert_equals(desc.get.call({}), undefined,
|
assert_equals(desc.get.call({}), undefined,
|
||||||
"calling getter on wrong object type must return undefined");
|
"calling getter on wrong object type must return undefined");
|
||||||
|
@ -1748,6 +1779,8 @@ IdlInterface.prototype.do_interface_attribute_asserts = function(obj, member)
|
||||||
// value 1."
|
// value 1."
|
||||||
assert_equals(desc.set.length, 1, "setter length must be 1");
|
assert_equals(desc.set.length, 1, "setter length must be 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Promise.all(pendingPromises).then(a_test.done.bind(a_test));
|
||||||
}
|
}
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче