diff options
author | Refael Ackermann <refack@gmail.com> | 2017-04-27 21:57:12 -0400 |
---|---|---|
committer | Refael Ackermann <refack@gmail.com> | 2017-06-10 22:49:28 -0400 |
commit | af3aa682ac534bb55765f5fef2755a88e5ff2580 (patch) | |
tree | d632fb6f8347f58c05731d16374b05706ef828ba /test/parallel/test-util-callbackify.js | |
parent | 780acc2208a3cdd3b01ae93aeaa478771fd3fd56 (diff) | |
download | android-node-v8-af3aa682ac534bb55765f5fef2755a88e5ff2580.tar.gz android-node-v8-af3aa682ac534bb55765f5fef2755a88e5ff2580.tar.bz2 android-node-v8-af3aa682ac534bb55765f5fef2755a88e5ff2580.zip |
util: add callbackify
Add `util.callbackify(function)` for creating callback style functions
from functions returning a `Thenable`
PR-URL: https://github.com/nodejs/node/pull/12712
Fixes: https://github.com/nodejs/CTC/issues/109
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Teddy Katz <teddy.katz@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'test/parallel/test-util-callbackify.js')
-rw-r--r-- | test/parallel/test-util-callbackify.js | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/test/parallel/test-util-callbackify.js b/test/parallel/test-util-callbackify.js new file mode 100644 index 0000000000..fa793d4a7f --- /dev/null +++ b/test/parallel/test-util-callbackify.js @@ -0,0 +1,227 @@ +'use strict'; +const common = require('../common'); + +// This test checks that the semantics of `util.callbackify` are as described in +// the API docs + +const assert = require('assert'); +const { callbackify } = require('util'); +const { join } = require('path'); +const { execFile } = require('child_process'); +const fixtureDir = join(common.fixturesDir, 'uncaught-exceptions'); +const values = [ + 'hello world', + null, + undefined, + false, + 0, + {}, + { key: 'value' }, + Symbol('I am a symbol'), + function ok() {}, + ['array', 'with', 4, 'values'], + new Error('boo') +]; + +{ + // Test that the resolution value is passed as second argument to callback + for (const value of values) { + // Test and `async function` + async function asyncFn() { + return await Promise.resolve(value); + } + + const cbAsyncFn = callbackify(asyncFn); + cbAsyncFn(common.mustCall((err, ret) => { + assert.ifError(err); + assert.strictEqual(ret, value); + })); + + // Test Promise factory + function promiseFn() { + return Promise.resolve(value); + } + + const cbPromiseFn = callbackify(promiseFn); + cbPromiseFn(common.mustCall((err, ret) => { + assert.ifError(err); + assert.strictEqual(ret, value); + })); + + // Test Thenable + function thenableFn() { + return { + then(onRes, onRej) { + onRes(value); + } + }; + } + + const cbThenableFn = callbackify(thenableFn); + cbThenableFn(common.mustCall((err, ret) => { + assert.ifError(err); + assert.strictEqual(ret, value); + })); + } +} + +{ + // Test that rejection reason is passed as first argument to callback + for (const value of values) { + // Test an `async function` + async function asyncFn() { + return await Promise.reject(value); + } + + const cbAsyncFn = callbackify(asyncFn); + cbAsyncFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + + // test a Promise factory + function promiseFn() { + return Promise.reject(value); + } + + const cbPromiseFn = callbackify(promiseFn); + cbPromiseFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + + // Test Thenable + function thenableFn() { + return { + then(onRes, onRej) { + onRej(value); + } + }; + } + + const cbThenableFn = callbackify(thenableFn); + cbThenableFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + } +} + +{ + // Test that arguments passed to callbackified function are passed to original + for (const value of values) { + async function asyncFn(arg) { + assert.strictEqual(arg, value); + return await Promise.resolve(arg); + } + + const cbAsyncFn = callbackify(asyncFn); + cbAsyncFn(value, common.mustCall((err, ret) => { + assert.ifError(err); + assert.strictEqual(ret, value); + })); + + function promiseFn(arg) { + assert.strictEqual(arg, value); + return Promise.resolve(arg); + } + + const cbPromiseFn = callbackify(promiseFn); + cbPromiseFn(value, common.mustCall((err, ret) => { + assert.ifError(err); + assert.strictEqual(ret, value); + })); + } +} + +{ + // Test that `this` binding is the same for callbackified and original + for (const value of values) { + const iAmThis = { + fn(arg) { + assert.strictEqual(this, iAmThis); + return Promise.resolve(arg); + }, + }; + iAmThis.cbFn = callbackify(iAmThis.fn); + iAmThis.cbFn(value, common.mustCall(function(err, ret) { + assert.ifError(err); + assert.strictEqual(ret, value); + assert.strictEqual(this, iAmThis); + })); + + const iAmThat = { + async fn(arg) { + assert.strictEqual(this, iAmThat); + return await Promise.resolve(arg); + }, + }; + iAmThat.cbFn = callbackify(iAmThat.fn); + iAmThat.cbFn(value, common.mustCall(function(err, ret) { + assert.ifError(err); + assert.strictEqual(ret, value); + assert.strictEqual(this, iAmThat); + })); + } +} + +{ + // Test that callback that throws emits an `uncaughtException` event + const fixture = join(fixtureDir, 'callbackify1.js'); + execFile( + process.execPath, + [fixture], + common.mustCall((err, stdout, stderr) => { + assert.strictEqual(err.code, 1); + assert.strictEqual(Object.getPrototypeOf(err).name, 'Error'); + assert.strictEqual(stdout, ''); + const errLines = stderr.trim().split(/[\r\n]+/g); + const errLine = errLines.find((l) => /^Error/.exec(l)); + assert.strictEqual(errLine, `Error: ${fixture}`); + }) + ); +} + +{ + // Test that handled `uncaughtException` works and passes rejection reason + const fixture = join(fixtureDir, 'callbackify2.js'); + execFile( + process.execPath, + [fixture], + common.mustCall((err, stdout, stderr) => { + assert.ifError(err); + assert.strictEqual(stdout.trim(), fixture); + assert.strictEqual(stderr, ''); + }) + ); +} |