summaryrefslogtreecommitdiff
path: root/test/parallel/test-util-callbackify.js
diff options
context:
space:
mode:
authorRefael Ackermann <refack@gmail.com>2017-04-27 21:57:12 -0400
committerRefael Ackermann <refack@gmail.com>2017-06-10 22:49:28 -0400
commitaf3aa682ac534bb55765f5fef2755a88e5ff2580 (patch)
treed632fb6f8347f58c05731d16374b05706ef828ba /test/parallel/test-util-callbackify.js
parent780acc2208a3cdd3b01ae93aeaa478771fd3fd56 (diff)
downloadandroid-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.js227
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, '');
+ })
+ );
+}