// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
var BUGNUMBER = 1180306;
var summary = 'Promise.{all,race} should close iterator on error' ;
print(BUGNUMBER + ": " + summary);
function test(ctor, props, { nextVal=undefined,
nextThrowVal=undefined,
modifier=undefined,
rejectReason=undefined,
rejectType=undefined,
closed=true }) {
function getIterable() {
let iterable = {
closed: false ,
[Symbol.iterator]() {
let iterator = {
first: true ,
next() {
if (this .first) {
this .first = false ;
if (nextThrowVal)
throw nextThrowVal;
return nextVal;
}
return { value: undefined, done: true };
},
return () {
iterable.closed = true ;
return {};
}
};
if (modifier)
modifier(iterator, iterable);
return iterator;
}
};
return iterable;
}
for (let prop of props) {
let iterable = getIterable();
let e;
ctor[prop](iterable).catch (e_ => { e = e_; });
drainJobQueue();
if (rejectType)
assertEq(e instanceof rejectType, true );
else
assertEq(e, rejectReason);
assertEq(iterable.closed, closed);
}
}
// == Error cases with close ==
// ES 2017 draft 25.4.4.1.1 step 6.i.
// ES 2017 draft 25.4.4.3.1 step 3.h.
class MyPromiseStaticResolveGetterThrows extends Promise {
static get resolve() {
throw "static resolve getter throws" ;
}
};
test(MyPromiseStaticResolveGetterThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
rejectReason: "static resolve getter throws" ,
closed: false ,
});
class MyPromiseStaticResolveThrows extends Promise {
static resolve() {
throw "static resolve throws" ;
}
};
test(MyPromiseStaticResolveThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
rejectReason: "static resolve throws" ,
closed: true ,
});
// ES 2017 draft 25.4.4.1.1 step 6.q.
// ES 2017 draft 25.4.4.3.1 step 3.i.
class MyPromiseThenGetterThrows extends Promise {
static resolve() {
return {
get then() {
throw "then getter throws" ;
}
};
}
};
test(MyPromiseThenGetterThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
rejectReason: "then getter throws" ,
closed: true ,
});
class MyPromiseThenThrows extends Promise {
static resolve() {
return {
then() {
throw "then throws" ;
}
};
}
};
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
rejectReason: "then throws" ,
closed: true ,
});
// ES 2017 draft 7.4.6 step 3.
// if GetMethod fails, the thrown value should be used.
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
modifier: (iterator, iterable) => {
Object.defineProperty(iterator, "return" , {
get: function () {
iterable.closed = true ;
throw "return getter throws" ;
}
});
},
rejectReason: "return getter throws" ,
closed: true ,
});
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
modifier: (iterator, iterable) => {
Object.defineProperty(iterator, "return" , {
get: function () {
iterable.closed = true ;
return "non object" ;
}
});
},
rejectType: TypeError,
closed: true ,
});
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
modifier: (iterator, iterable) => {
Object.defineProperty(iterator, "return" , {
get: function () {
iterable.closed = true ;
// Non callable.
return {};
}
});
},
rejectType: TypeError,
closed: true ,
});
// ES 2017 draft 7.4.6 steps 6.
// if return method throws, the thrown value should be ignored.
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
modifier: (iterator, iterable) => {
iterator.return = function () {
iterable.closed = true ;
throw "return throws" ;
};
},
rejectReason: "then throws" ,
closed: true ,
});
test(MyPromiseThenThrows, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
modifier: (iterator, iterable) => {
iterator.return = function () {
iterable.closed = true ;
return "non object" ;
};
},
rejectReason: "then throws" ,
closed: true ,
});
// == Error cases without close ==
// ES 2017 draft 25.4.4.1.1 step 6.a.
test(Promise, ["all" , "race" ], {
nextThrowVal: "next throws" ,
rejectReason: "next throws" ,
closed: false ,
});
test(Promise, ["all" , "race" ], {
nextVal: { value: {}, get done() { throw "done getter throws" ; } },
rejectReason: "done getter throws" ,
closed: false ,
});
// ES 2017 draft 25.4.4.1.1 step 6.e.
test(Promise, ["all" , "race" ], {
nextVal: { get value() { throw "value getter throws" ; }, done: false },
rejectReason: "value getter throws" ,
closed: false ,
});
// ES 2017 draft 25.4.4.1.1 step 6.d.iii.2.
let first = true ;
class MyPromiseResolveThrows extends Promise {
constructor(executer) {
if (first) {
first = false ;
super ((resolve, reject) => {
executer(() => {
throw "resolve throws" ;
}, reject);
});
return ;
}
super (executer);
}
};
test(MyPromiseResolveThrows, ["all" ], {
nextVal: { value: undefined, done: true },
rejectReason: "resolve throws" ,
closed: false ,
});
// == Successful cases ==
test(Promise, ["all" , "race" ], {
nextVal: { value: Promise.resolve(1), done: false },
closed: false ,
});
if (typeof reportCompare === 'function' )
reportCompare(true , true );
Messung V0.5 C=86 H=97 G=91
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland