From 89e59e067f4576ca0830abf77db4da0a0d0acf01 Mon Sep 17 00:00:00 2001
From: Cameron Little <cameron@camlittle.com>
Date: Mon, 13 Mar 2017 09:04:54 -0700
Subject: [PATCH 1/2] test: support multiple warnings in common.checkWarning

This allows the common.checkWarning() test method to accept a map of
warning names to description(s), to allow testing code that generates
multiple types of warnings.
---
 test/common.js | 42 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/test/common.js b/test/common.js
index 8f19efd900abf7..842abe2aab75ae 100644
--- a/test/common.js
+++ b/test/common.js
@@ -600,17 +600,45 @@ exports.isAlive = function isAlive(pid) {
   }
 };
 
-exports.expectWarning = function(name, expected) {
-  if (typeof expected === 'string')
-    expected = [expected];
-  process.on('warning', exports.mustCall((warning) => {
+function expectWarning(name, expectedMessages) {
+  return exports.mustCall((warning) => {
     assert.strictEqual(warning.name, name);
-    assert.ok(expected.includes(warning.message),
+    assert.ok(expectedMessages.includes(warning.message),
               `unexpected error message: "${warning.message}"`);
     // Remove a warning message after it is seen so that we guarantee that we
     // get each message only once.
-    expected.splice(expected.indexOf(warning.message), 1);
-  }, expected.length));
+    expectedMessages.splice(expectedMessages.indexOf(warning.message), 1);
+  }, expectedMessages.length);
+}
+
+function expectWarningByName(name, expected) {
+  if (typeof expected === 'string') {
+    expected = [expected];
+  }
+  process.on('warning', expectWarning(name, expected));
+}
+
+function expectWarningByMap(warningMap) {
+  const catchWarning = {};
+  Object.keys(warningMap).forEach((name) => {
+    let expected = warningMap[name];
+    if (typeof expected === 'string') {
+      expected = [expected];
+    }
+    catchWarning[name] = expectWarning(name, expected);
+  });
+  process.on('warning', (warning) => catchWarning[warning.name](warning));
+}
+
+// accepts a warning name and description or array of descriptions or a map
+// of warning names to description(s)
+// ensures a warning is generated for each name/description pair
+exports.expectWarning = function(nameOrMap, expected) {
+  if (typeof nameOrMap === 'string') {
+    expectWarningByName(nameOrMap, expected);
+  } else {
+    expectWarningByMap(nameOrMap);
+  }
 };
 
 Object.defineProperty(exports, 'hasIntl', {

From 840021c0ef5a01632c1f72cf9ad62ad5417381fc Mon Sep 17 00:00:00 2001
From: Cameron Little <cameron@camlittle.com>
Date: Mon, 13 Mar 2017 09:07:06 -0700
Subject: [PATCH 2/2] process: Cast promise rejection reason to string

The unhandled promise rejection warning uses a template literal and
prints the reason a promise was rejected. If rejecting with a symbol,
the symbol failed to convert to a string and the process crashed. Now,
symbols are casted to strings and the process does not crash.

Fixes: https://github.com/nodejs/node/issues/11637
---
 lib/internal/process/promises.js               |  2 +-
 ...est-promises-unhandled-symbol-rejections.js | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)
 create mode 100644 test/parallel/test-promises-unhandled-symbol-rejections.js

diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js
index 0e382d11d5523b..1ba4aa47f575bf 100644
--- a/lib/internal/process/promises.js
+++ b/lib/internal/process/promises.js
@@ -57,7 +57,7 @@ function setupPromises(scheduleMicrotasks) {
 
   function emitWarning(uid, reason) {
     const warning = new Error('Unhandled promise rejection ' +
-                              `(rejection id: ${uid}): ${reason}`);
+                              `(rejection id: ${uid}): ${String(reason)}`);
     warning.name = 'UnhandledPromiseRejectionWarning';
     warning.id = uid;
     if (reason instanceof Error) {
diff --git a/test/parallel/test-promises-unhandled-symbol-rejections.js b/test/parallel/test-promises-unhandled-symbol-rejections.js
new file mode 100644
index 00000000000000..a60a5f2e8aac30
--- /dev/null
+++ b/test/parallel/test-promises-unhandled-symbol-rejections.js
@@ -0,0 +1,18 @@
+'use strict';
+const common = require('../common');
+
+const expectedDeprecationWarning = 'Unhandled promise rejections are ' +
+                                   'deprecated. In the future, promise ' +
+                                   'rejections that are not handled will ' +
+                                   'terminate the Node.js process with a ' +
+                                   'non-zero exit code.';
+const expectedPromiseWarning = 'Unhandled promise rejection (rejection id: ' +
+                               '1): Symbol()';
+
+common.expectWarning({
+  DeprecationWarning: expectedDeprecationWarning,
+  UnhandledPromiseRejectionWarning: expectedPromiseWarning,
+});
+
+// ensure this doesn't crash
+Promise.reject(Symbol());