Browse Source

Merge pull request #1864 from svaarala/promise-testcase-improvements

Promise testcase improvements
pull/1865/head
Sami Vaarala 7 years ago
committed by GitHub
parent
commit
3fafc9bd49
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      polyfills/promise.js
  2. 10
      tests/ecmascript/test-bi-math-log2-2n.js
  3. 2
      tests/ecmascript/test-bi-nodejs-buffer-tostring.js
  4. 27
      tests/ecmascript/test-bi-promise-constructor-all-empty.js
  5. 0
      tests/ecmascript/test-bi-promise-constructor-all-fulfill.js
  6. 0
      tests/ecmascript/test-bi-promise-constructor-all-iterable-error.js
  7. 0
      tests/ecmascript/test-bi-promise-constructor-all-iterable.js
  8. 0
      tests/ecmascript/test-bi-promise-constructor-all-reject.js
  9. 29
      tests/ecmascript/test-bi-promise-constructor-all-thenable.js
  10. 5
      tests/ecmascript/test-bi-promise-constructor-properties.js
  11. 0
      tests/ecmascript/test-bi-promise-constructor-race-fulfill-iterable-error.js
  12. 0
      tests/ecmascript/test-bi-promise-constructor-race-fulfill-iterable.js
  13. 0
      tests/ecmascript/test-bi-promise-constructor-race-fulfill-multiple.js
  14. 0
      tests/ecmascript/test-bi-promise-constructor-race-fulfill-reject-none.js
  15. 0
      tests/ecmascript/test-bi-promise-constructor-race-fulfill-single.js
  16. 0
      tests/ecmascript/test-bi-promise-constructor-race-reject-multiple.js
  17. 0
      tests/ecmascript/test-bi-promise-constructor-race-reject-single.js
  18. 32
      tests/ecmascript/test-bi-promise-constructor-reject-noarg.js
  19. 25
      tests/ecmascript/test-bi-promise-constructor-resolve-noarg.js
  20. 39
      tests/ecmascript/test-bi-promise-constructor-retval.js
  21. 34
      tests/ecmascript/test-bi-promise-resolve-self-resolution-settled.js
  22. 20
      tests/memory/test-promise-instance-resolve-reject.js
  23. 18
      tests/memory/test-promise-pending.js
  24. 17
      tests/memory/test-promise-rejected.js
  25. 17
      tests/memory/test-promise-resolved.js
  26. 22
      tests/memory/test-promise-then-chain.js
  27. 43
      tests/perf/test-mandel-iter10-normal.js
  28. 65
      tests/perf/test-mandel-iter10-promise.js
  29. 65
      tests/perf/test-mandel-promise.js

29
polyfills/promise.js

@ -19,7 +19,7 @@
*/
(function () {
if ('Promise' in this) { return; }
if (typeof Promise !== 'undefined') { return; }
// Job queue to simulate ES2015 job queues, linked list, 'next' reference.
// While ES2015 doesn't guarantee the relative order of jobs in different
@ -30,10 +30,14 @@
// multiple Job Queues are serviced."
var queueHead = null, queueTail = null;
function enqueueJob(job) {
compact(job);
if (queueHead) {
queueTail.next = job; queueTail = job;
queueTail.next = job;
compact(queueTail);
queueTail = job;
} else {
queueHead = job; queueTail = job;
queueHead = job;
queueTail = job;
}
}
function dequeueJob() {
@ -47,7 +51,7 @@
return ret;
}
// Helper to define non-enumerable properties.
// Helper to define/modify properties more compactly.
function def(obj, key, val, attrs) {
if (attrs === void 0) { attrs = 'wc'; }
Object.defineProperty(obj, key, {
@ -58,6 +62,10 @@
});
}
// Helper for Duktape specific object compaction.
var compact = (typeof Duktape === 'object' && Duktape.compact) ||
function (v) { return v; };
// Promise detection (plain or subclassed Promise), in spec has
// [[PromiseState]] internal slot which isn't affected by Proxy
// behaviors etc.
@ -74,7 +82,7 @@
if (p.state !== void 0) { return; } // should not happen
p.state = true; p.value = val;
var reactions = p.fulfillReactions;
delete p.fulfillReactions; delete p.rejectReactions;
delete p.fulfillReactions; delete p.rejectReactions; compact(p);
reactions.forEach(function (r) {
enqueueJob({
handler: r.handler,
@ -88,7 +96,7 @@
if (p.state !== void 0) { return; } // should not happen
p.state = false; p.value = val;
var reactions = p.rejectReactions;
delete p.fulfillReactions; delete p.rejectReactions;
delete p.fulfillReactions; delete p.rejectReactions; compact(p);
reactions.forEach(function (r) {
enqueueJob({
handler: r.handler,
@ -106,7 +114,7 @@
// to be settled but check it anyway: it may be useful for e.g. the C API
// to forcibly resolve/fulfill/reject a Promise regardless of extant
// resolve/reject functions.
function getResolutionFunctions(p) {
function createResolutionFunctions(p) {
// In ES2015 the resolve/reject functions have a shared 'state' object
// with a [[AlreadyResolved]] slot. Here we use an in-scope variable.
var alreadyResolved = false;
@ -127,7 +135,7 @@
var then = (val !== null && typeof val === 'object' &&
val.then);
if (typeof then === 'function') {
var t = getResolutionFunctions(p);
var t = createResolutionFunctions(p);
return enqueueJob({
thenable: val,
then: then,
@ -187,7 +195,8 @@
def(this, 'value', void 0);
def(this, 'fulfillReactions', []);
def(this, 'rejectReactions', []);
var t = getResolutionFunctions(this);
compact(this);
var t = createResolutionFunctions(this);
try {
void executor(t.resolve, t.reject);
} catch (e) {
@ -324,5 +333,7 @@
def(cons, 'runQueue', function _runQueueUntilEmpty() {
while (runQueueEntry()) {}
});
compact(this); compact(cons); compact(proto);
}());
}());

10
tests/ecmascript/test-bi-math-log2-2n.js

@ -13,21 +13,21 @@ function test() {
for (expect = 0, x = 1; x !== 1/0; x *= 2, expect++) {
if (Math.log2(x) != expect) {
console.log('FAIL', x, Math.log2(x));
print('FAIL', x, Math.log2(x));
}
}
console.log('positive exponents done');
print('positive exponents done');
for (expect = 0, x = 1; x !== 0; x /= 2, expect--) {
if (Math.log2(x) != expect) {
console.log('FAIL', x, Math.log2(x));
print('FAIL', x, Math.log2(x));
}
}
console.log('negative exponents done');
print('negative exponents done');
}
try {
test();
} catch (e) {
console.log(e.stack || e);
print(e.stack || e);
}

2
tests/ecmascript/test-bi-nodejs-buffer-tostring.js

@ -643,7 +643,7 @@ function miscDecodeTest() {
function test(bytes) {
var buf = makeBuffer(bytes);
console.log(Array.prototype.map.call(buf.toString(), function (v) { return v.charCodeAt(0); }).join(' '));
print(Array.prototype.map.call(buf.toString(), function (v) { return v.charCodeAt(0); }).join(' '));
}
// All initial bytes.

27
tests/ecmascript/test-bi-promise-constructor-all-empty.js

@ -0,0 +1,27 @@
/*---
{
"skip": true
}
---*/
/*===
done
fulfill
object
[object Array]
0
===*/
// Empty list is an important corner case, and also exercises the specific
// .all() path where an immediate completion is checked for.
Promise.all([]).then(function (v) {
print('fulfill');
print(typeof v);
print(Object.prototype.toString.call(v));
print(v.length);
}, function (e) {
print('reject:', e);
});
print('done');

0
tests/ecmascript/test-bi-promise-all-fulfill.js → tests/ecmascript/test-bi-promise-constructor-all-fulfill.js

0
tests/ecmascript/test-bi-promise-all-iterable-error.js → tests/ecmascript/test-bi-promise-constructor-all-iterable-error.js

0
tests/ecmascript/test-bi-promise-all-iterable.js → tests/ecmascript/test-bi-promise-constructor-all-iterable.js

0
tests/ecmascript/test-bi-promise-all-reject.js → tests/ecmascript/test-bi-promise-constructor-all-reject.js

29
tests/ecmascript/test-bi-promise-constructor-all-thenable.js

@ -0,0 +1,29 @@
/*---
{
"skip": true
}
---*/
/*===
done
O1.then
O2.then
Promise.all then
2 123 234
===*/
var O1CB, O2CB;
var O1 = { then: function (cb) { print('O1.then'); O1CB = cb; } };
var O2 = { then: function (cb) { print('O2.then'); O2CB = cb; } };
var P = Promise.all([ O1, O2 ]);
P.then(function (v) {
print('Promise.all then');
print(v.length, v[0], v[1]);
});
Promise.resolve().then(function () {
O1CB(123);
O2CB(234);
});
print('done');

5
tests/ecmascript/test-bi-promise-constructor-properties.js

@ -14,6 +14,7 @@ Promise
true
true
propdesc Promise: value=function:Promise, writable=true, enumerable=false, configurable=true
true
- properties
propdesc length: value=1, writable=false, enumerable=false, configurable=true
propdesc name: value="Promise", writable=false, enumerable=false, configurable=true
@ -22,6 +23,7 @@ propdesc all: value=function:all, writable=true, enumerable=false, configurable=
propdesc race: value=function:race, writable=true, enumerable=false, configurable=true
propdesc reject: value=function:reject, writable=true, enumerable=false, configurable=true
propdesc resolve: value=function:resolve, writable=true, enumerable=false, configurable=true
done
===*/
// General.
@ -34,6 +36,7 @@ print(Promise.name);
print('Promise' in GLOBAL);
print(Object.getPrototypeOf(Promise) === Function.prototype);
print(Test.getPropDescString(GLOBAL, 'Promise'));
print(Object.getPrototypeOf(new Promise(function () {})) === Promise.prototype);
print('- properties');
print(Test.getPropDescString(Promise, 'length'));
@ -44,3 +47,5 @@ print(Test.getPropDescString(Promise, 'race'));
print(Test.getPropDescString(Promise, 'reject'));
print(Test.getPropDescString(Promise, 'resolve'));
// @@species separately
print('done');

0
tests/ecmascript/test-bi-promise-race-iterable-error.js → tests/ecmascript/test-bi-promise-constructor-race-fulfill-iterable-error.js

0
tests/ecmascript/test-bi-promise-race-iterable.js → tests/ecmascript/test-bi-promise-constructor-race-fulfill-iterable.js

0
tests/ecmascript/test-bi-promise-race-fulfill-multiple.js → tests/ecmascript/test-bi-promise-constructor-race-fulfill-multiple.js

0
tests/ecmascript/test-bi-promise-race-fulfill-reject-none.js → tests/ecmascript/test-bi-promise-constructor-race-fulfill-reject-none.js

0
tests/ecmascript/test-bi-promise-race-fulfill-single.js → tests/ecmascript/test-bi-promise-constructor-race-fulfill-single.js

0
tests/ecmascript/test-bi-promise-race-reject-multiple.js → tests/ecmascript/test-bi-promise-constructor-race-reject-multiple.js

0
tests/ecmascript/test-bi-promise-race-reject-single.js → tests/ecmascript/test-bi-promise-constructor-race-reject-single.js

32
tests/ecmascript/test-bi-promise-constructor-reject-noarg.js

@ -0,0 +1,32 @@
/*---
{
"skip": true
}
---*/
/*===
done
fulfill, values match true
2 undefined undefined
===*/
// Missing argument and void 0 are handled the same.
var P = Promise.reject();
var Q = Promise.reject(void 0);
var T1 = P.catch(function (e) {
return e;
});
var T2 = Q.catch(function (e) {
return e;
});
Promise.all([ T1, T2 ]).then(function (v) {
print('fulfill, values match', v[0] === v[1]);
print(v.length, v[0], v[1]);
}, function (e) {
print('reject:', e);
});
print('done');

25
tests/ecmascript/test-bi-promise-constructor-resolve-noarg.js

@ -0,0 +1,25 @@
/*---
{
"skip": true
}
---*/
/*===
done
fulfill, values match true
2 undefined undefined
===*/
// Missing argument and void 0 are handled the same.
var P = Promise.resolve();
var Q = Promise.resolve(void 0);
Promise.all([ P, Q ]).then(function (v) {
print('fulfill, values match', v[0] === v[1]);
print(v.length, v[0], v[1]);
}, function (e) {
print('reject:', e);
});
print('done');

39
tests/ecmascript/test-bi-promise-constructor-retval.js

@ -0,0 +1,39 @@
/*---
{
"skip": true
}
---*/
/*===
done
Q fulfill: 321
===*/
// Promise executor return value has no effect on promise value.
var resolveP, rejectP;
var resolveQ, rejectQ;
var P = new Promise(function (resolve, reject) {
resolveP = resolve;
rejectP = reject;
return 123; // return value won't resolve P
});
P.then(function (v) {
print('P fulfill:', v);
}, function (e) {
print('P reject:', e);
});
var Q = new Promise(function (resolve, reject) {
resolveQ = resolve;
rejectQ = reject;
return 123;
});
Q.then(function (v) {
print('Q fulfill:', v);
}, function (e) {
print('Q reject:', e);
});
resolveQ(321);
print('done');

34
tests/ecmascript/test-bi-promise-resolve-self-resolution-settled.js

@ -0,0 +1,34 @@
/*---
{
"skip": true
}
---*/
/*===
ignored
done
fulfill: 123
===*/
var resolveFn;
var P = new Promise(function (resolve, reject) {
resolveFn = resolve;
});
P.then(function (v) {
print('fulfill:', v);
}, function (e) {
print('reject:', e.name);
});
resolveFn(123);
// Self resolution after already being settled is a no-op.
try {
resolveFn(P);
print('ignored');
} catch (e) {
print('should not happen:', e);
}
print('done');

20
tests/memory/test-promise-instance-resolve-reject.js

@ -0,0 +1,20 @@
// Footprint of a Promise object and its resolve/reject function objects.
function test() {
var promises = [];
var resolves = [];
var rejects = [];
var executor = function (resolve, reject) { resolves.push(resolve); rejects.push(reject); };
while (promises.length < 1e5) {
if ((promises.length % 100) == 0) {
Duktape.gc();
}
promises.push(new Promise(executor));
}
Duktape.gc();
print(promises.length + ' Promises created');
}
test();

18
tests/memory/test-promise-pending.js

@ -0,0 +1,18 @@
// Footprint of a pending Promise object, no resolve/reject functions.
function test() {
var promises = [];
function nop() {}
while (promises.length < 1e5) {
if ((promises.length % 100) == 0) {
Duktape.gc();
}
promises.push(new Promise(nop));
}
Duktape.gc();
print(promises.length + ' Promises created');
}
test();

17
tests/memory/test-promise-rejected.js

@ -0,0 +1,17 @@
// Footprint of a rejected Promise object, no resolve/reject functions.
function test() {
var promises = [];
while (promises.length < 1e5) {
if ((promises.length % 100) == 0) {
Duktape.gc();
}
promises.push(Promise.reject(123));
}
Duktape.gc();
print(promises.length + ' Promises created');
}
test();

17
tests/memory/test-promise-resolved.js

@ -0,0 +1,17 @@
// Footprint of a resolved Promise object, no resolve/reject functions.
function test() {
var promises = [];
while (promises.length < 1e5) {
if ((promises.length % 100) == 0) {
Duktape.gc();
}
promises.push(Promise.resolve(123));
}
Duktape.gc();
print(promises.length + ' Promises created');
}
test();

22
tests/memory/test-promise-then-chain.js

@ -0,0 +1,22 @@
// Footprint of an unresolved long .then() chain.
function test() {
var count = 1e3;
function id(v) { return v; }
// Root and entire chain will remain unresolved.
var root = new Promise(function () {});
var curr = root;
for (var i = 0; i < count; i++) {
if ((i % 100) == 0) {
Duktape.gc();
}
curr = curr.then(id);
}
Duktape.gc();
print(count + ' Promises created');
}
test();

43
tests/perf/test-mandel-iter10-normal.js

@ -0,0 +1,43 @@
if (typeof print !== 'function') { print = console.log; }
function mandel() {
var w = 200, h = 200, iter = 10;
var i, j, k, c;
var x0, y0, xx, yy, xx2, yy2;
var line;
for (i = 0; i < h; i++) {
y0 = (i / h) * 2.5 - 1.25;
for (j = 0, line = []; j < w; j++) {
x0 = (j / w) * 3.0 - 2.0;
for (k = 0, xx = 0, yy = 0, c = '#'; k < iter; k++) {
xx2 = xx*xx; yy2 = yy*yy;
if (xx2 + yy2 < 4.0) {
yy = 2*xx*yy + y0;
xx = xx2 - yy2 + x0;
} else {
/* xx^2 + yy^2 >= 4.0 */
if (k < 3) { c = '.'; }
else if (k < 5) { c = ','; }
else if (k < 10) { c = '-'; }
else { c = '='; }
break;
}
}
line.push(c);
}
print(line.join(''));
}
}
try {
mandel();
} catch (e) {
print(e.stack || e);
throw e;
}

65
tests/perf/test-mandel-iter10-promise.js

@ -0,0 +1,65 @@
if (typeof print !== 'function') { print = console.log; }
var jobs = [];
function runJob(job) {
var iter = 10, k, c, xx, yy, xx2, yy2, x0 = job.x0, y0 = job.y0;
for (k = 0, xx = 0, yy = 0, c = '#'; k < iter; k++) {
xx2 = xx*xx; yy2 = yy*yy;
if (xx2 + yy2 < 4.0) {
yy = 2*xx*yy + y0;
xx = xx2 - yy2 + x0;
} else {
/* xx^2 + yy^2 >= 4.0 */
if (k < 3) { c = '.'; }
else if (k < 5) { c = ','; }
else if (k < 10) { c = '-'; }
else { c = '='; }
job.resolve(c);
return;
}
}
job.resolve('#');
}
function createMandelPromise() {
var w = 200, h = 200;
var i, j;
var x0, y0;
var row;
var rows = [];
var P;
for (i = 0; i < h; i++) {
y0 = (i / h) * 2.5 - 1.25;
for (j = 0, row = []; j < w; j++) {
x0 = (j / w) * 3.0 - 2.0;
P = new Promise(function (resolve, reject) {
jobs.push({ x0: x0, y0: y0, resolve: resolve, reject: reject });
});
row.push(P);
}
rows.push(Promise.all(row));
}
return Promise.all(rows);
}
try {
createMandelPromise().then(function (rows) {
rows.forEach(function (row) {
print(row.join(''));
});
}, function (e) {
print(e);
});
jobs.forEach(runJob);
} catch (e) {
print(e.stack || e);
throw e;
}

65
tests/perf/test-mandel-promise.js

@ -0,0 +1,65 @@
if (typeof print !== 'function') { print = console.log; }
var jobs = [];
function runJob(job) {
var iter = 100000, k, c, xx, yy, xx2, yy2, x0 = job.x0, y0 = job.y0;
for (k = 0, xx = 0, yy = 0, c = '#'; k < iter; k++) {
xx2 = xx*xx; yy2 = yy*yy;
if (xx2 + yy2 < 4.0) {
yy = 2*xx*yy + y0;
xx = xx2 - yy2 + x0;
} else {
/* xx^2 + yy^2 >= 4.0 */
if (k < 3) { c = '.'; }
else if (k < 5) { c = ','; }
else if (k < 10) { c = '-'; }
else { c = '='; }
job.resolve(c);
return;
}
}
job.resolve('#');
}
function createMandelPromise() {
var w = 76, h = 28;
var i, j;
var x0, y0;
var row;
var rows = [];
var P;
for (i = 0; i < h; i++) {
y0 = (i / h) * 2.5 - 1.25;
for (j = 0, row = []; j < w; j++) {
x0 = (j / w) * 3.0 - 2.0;
P = new Promise(function (resolve, reject) {
jobs.push({ x0: x0, y0: y0, resolve: resolve, reject: reject });
});
row.push(P);
}
rows.push(Promise.all(row));
}
return Promise.all(rows);
}
try {
createMandelPromise().then(function (rows) {
rows.forEach(function (row) {
print(row.join(''));
});
}, function (e) {
print(e);
});
jobs.forEach(runJob);
} catch (e) {
print(e.stack || e);
throw e;
}
Loading…
Cancel
Save