[Pkg-javascript-commits] [node-string-decoder] 17/27: Updated to node v7.8.0.

Bastien Roucariès rouca at moszumanska.debian.org
Thu May 11 15:12:32 UTC 2017


This is an automated email from the git hooks/post-receive script.

rouca pushed a commit to branch master
in repository node-string-decoder.

commit 1ea0385ee50493cf4d64a9ec0bc6646903e3da2f
Author: Matteo Collina <hello at matteocollina.com>
Date:   Tue Apr 4 15:47:04 2017 +0200

    Updated to node v7.8.0.
---
 README.md                                |   7 -
 build/build.js                           | 165 +++++---
 build/files.js                           |  53 ++-
 build/package.json                       |  19 +-
 build/test-replacements.js               |  20 +
 index.js                                 | 200 ----------
 lib/string_decoder.js                    | 271 +++++++++++++
 package.json                             |   5 +-
 test/common.js                           | 650 ++++++++++++++++++++++++-------
 test/parallel/test-string-decoder-end.js |  58 +++
 test/parallel/test-string-decoder.js     | 174 +++++++++
 test/simple/test-string-decoder-end.js   |  75 ----
 test/simple/test-string-decoder.js       | 163 --------
 13 files changed, 1219 insertions(+), 641 deletions(-)

diff --git a/README.md b/README.md
index 4d2aa00..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +0,0 @@
-**string_decoder.js** (`require('string_decoder')`) from Node.js core
-
-Copyright Joyent, Inc. and other Node contributors. See LICENCE file for details.
-
-Version numbers match the versions found in Node core, e.g. 0.10.24 matches Node 0.10.24, likewise 0.11.10 matches Node 0.11.10. **Prefer the stable version over the unstable.**
-
-The *build/* directory contains a build script that will scrape the source from the [joyent/node](https://github.com/joyent/node) repo given a specific Node version.
\ No newline at end of file
diff --git a/build/build.js b/build/build.js
index 46470cf..f52fd28 100755
--- a/build/build.js
+++ b/build/build.js
@@ -1,45 +1,89 @@
 #!/usr/bin/env node
 
-const hyperquest  = require('hyperzip')(require('hyperdirect'))
+const hyperquest  = require('hyperquest')
     , bl          = require('bl')
     , fs          = require('fs')
     , path        = require('path')
-    , cheerio     = require('cheerio')
-
+    , tar         = require('tar-fs')
+    , gunzip      = require('gunzip-maybe')
+    , babel       = require('babel-core')
+    , glob        = require('glob')
+    , pump        = require('pump')
+    , rimraf      = require('rimraf')
+    , encoding    = 'utf8'
+    , urlRegex    = /^https?:\/\//
+    , nodeVersion = process.argv[2]
+    , nodeVersionRegexString = '\\d+\\.\\d+\\.\\d+'
+    , usageVersionRegex = RegExp('^' + nodeVersionRegexString + '$')
+    , readmeVersionRegex =
+        RegExp('((?:Node-core )|(?:https\:\/\/nodejs\.org\/dist\/)v)' + nodeVersionRegexString, 'g')
+
+    , readmePath  = path.join(__dirname, '..', 'README.md')
     , files       = require('./files')
     , testReplace = require('./test-replacements')
 
-    , srcurlpfx   = 'https://raw.github.com/joyent/node/v' + process.argv[2] + '-release/'
-    , libsrcurl   = srcurlpfx + 'lib/'
-    , testsrcurl  = srcurlpfx + 'test/simple/'
-    , testlisturl = 'https://github.com/joyent/node/tree/v' + process.argv[2] + '-release/test/simple'
-    , libourroot  = path.join(__dirname, '../')
-    , testourroot = path.join(__dirname, '../test/simple/')
+    , downloadurl = `https://nodejs.org/dist/v${nodeVersion}/node-v${nodeVersion}.tar.gz`
+    , src         = path.join(__dirname, `node-v${nodeVersion}`)
+    , libsrcurl   = path.join(src, 'lib/')
+    , testsrcurl  = path.join(src, 'test/parallel/')
+    , libourroot  = path.join(__dirname, '../lib/')
+    , testourroot = path.join(__dirname, '../test/parallel/')
 
 
-function processFile (url, out, replacements) {
-  hyperquest(url).pipe(bl(function (err, data) {
-    if (err)
-      throw err
+if (!usageVersionRegex.test(nodeVersion)) {
+  console.error('Usage: build.js xx.yy.zz')
+  return process.exit(1);
+}
+
+// `inputLoc`: URL or local path.
+function processFile (inputLoc, out, replacements) {
+  var file = fs.createReadStream(inputLoc, encoding)
 
+  file.pipe(bl(function (err, data) {
+    if (err) throw err
+
+    console.log('Processing', inputLoc)
     data = data.toString()
     replacements.forEach(function (replacement) {
-      data = data.replace.apply(data, replacement)
+      const regexp = replacement[0]
+      var arg2 = replacement[1]
+      if (typeof arg2 === 'function')
+        arg2 = arg2.bind(data)
+      data = data.replace(regexp, arg2)
     })
-
-    fs.writeFile(out, data, 'utf8', function (err) {
-      if (err)
-        throw err
+    if (inputLoc.slice(-3) === '.js') {
+      const transformed = babel.transform(data, {
+        plugins: [
+          'transform-es2015-parameters',
+          'transform-es2015-arrow-functions',
+          'transform-es2015-block-scoping',
+          'transform-es2015-template-literals',
+          'transform-es2015-shorthand-properties',
+          'transform-es2015-for-of',
+          'transform-es2015-destructuring'
+        ]
+      })
+      data = transformed.code
+    }
+    fs.writeFile(out, data, encoding, function (err) {
+      if (err) throw err
 
       console.log('Wrote', out)
     })
   }))
 }
-
+function deleteOldTests(){
+  const files = fs.readdirSync(path.join(__dirname, '..', 'test', 'parallel'));
+  for (let file of files) {
+    let name = path.join(__dirname, '..', 'test', 'parallel', file);
+    console.log('Removing', name);
+    fs.unlinkSync(name);
+  }
+}
 function processLibFile (file) {
   var replacements = files[file]
     , url          = libsrcurl + file
-    , out          = path.join(libourroot, replacements.out || file)
+    , out          = path.join(libourroot, file)
 
   processFile(url, out, replacements)
 }
@@ -56,39 +100,68 @@ function processTestFile (file) {
   processFile(url, out, replacements)
 }
 
+//--------------------------------------------------------------------
+// Download the release from nodejs.org
+console.log(`Downloading ${downloadurl}`)
+pump(
+  hyperquest(downloadurl),
+  gunzip(),
+  tar.extract(__dirname),
+  function (err) {
+    if (err) {
+      throw err
+    }
 
-if (!/0\.1\d\.\d+/.test(process.argv[2])) {
-  console.log('Usage: build.js <node version>')
-  return process.exit(-1)
-}
 
+    //--------------------------------------------------------------------
+    // Grab & process files in ../lib/
 
-//--------------------------------------------------------------------
-// Grab & process files in ../lib/
+    Object.keys(files).forEach(processLibFile)
 
-Object.keys(files).forEach(processLibFile)
 
-//--------------------------------------------------------------------
-// Discover, grab and process all test-string-decoder* files on joyent/node
+    //--------------------------------------------------------------------
+    // Discover, grab and process all test-stream* files on the given release
+
+    glob(path.join(testsrcurl, 'test-string-decoder*.js'), function (err, list) {
+      if (err) {
+        throw err
+      }
 
-hyperquest(testlisturl).pipe(bl(function (err, data) {
-  if (err)
-    throw err
+      list.forEach(function (file) {
+        file = path.basename(file)
+        processTestFile(file)
+      })
+    })
 
-  var $ = cheerio.load(data.toString())
 
-  $('table.files .js-directory-link').each(function () {
-    var file = $(this).text()
-    if (/^test-string-decoder/.test(file) || file == 'common.js')
-      processTestFile(file)
-  })
-}))
+    //--------------------------------------------------------------------
+    // Grab the nodejs/node test/common.js
 
-//--------------------------------------------------------------------
-// Grab the joyent/node test/common.js
+    processFile(
+        testsrcurl.replace(/parallel\/$/, 'common.js')
+      , path.join(testourroot, '../common.js')
+      , testReplace['common.js']
+    )
 
-processFile(
-    testsrcurl + '../common.js'
-  , path.join(testourroot, '../common.js')
-  , testReplace['common.js']
-)
\ No newline at end of file
+    //--------------------------------------------------------------------
+    // Update Node version in README
+
+    processFile(readmePath, readmePath, [
+      [readmeVersionRegex, "$1" + nodeVersion]
+    ])
+  }
+)
+
+// delete the current contents of test/parallel so if node removes any tests
+// they are removed here
+deleteOldTests();
+
+process.once('beforeExit', function () {
+  rimraf(src, function (err) {
+    if (err) {
+      throw err
+    }
+
+    console.log('Removed', src)
+  })
+})
diff --git a/build/files.js b/build/files.js
index 7396a4f..72407ce 100644
--- a/build/files.js
+++ b/build/files.js
@@ -8,13 +8,16 @@
 
 module.exports['string_decoder.js'] = [
 
-    // pull in Bufer as a require
-    // add Buffer.isEncoding where missing
+    // we do not need internal/util anymore
     [
-        /^(\/\/ USE OR OTHER DEALINGS IN THE SOFTWARE\.)/m
-      ,   '$1\n\nvar Buffer = require(\'buffer\').Buffer;'
-        + '\n'
-        + '\nvar isBufferEncoding = Buffer.isEncoding'
+        /const internalUtil = require\('internal\/util'\);/
+      , ''
+    ]
+
+    // add Buffer.isEncoding where missing
+  , [
+        /const isEncoding = Buffer\[internalUtil.kIsEncodingSymbol\];/
+      ,   '\nvar isEncoding = Buffer.isEncoding'
         + '\n  || function(encoding) {'
         + '\n       switch (encoding && encoding.toLowerCase()) {'
         + '\n         case \'hex\': case \'utf8\': case \'utf-8\': case \'ascii\': case \'binary\': case \'base64\': case \'ucs2\': case \'ucs-2\': case \'utf16le\': case \'utf-16le\': case \'raw\': return true;'
@@ -23,14 +26,46 @@ module.exports['string_decoder.js'] = [
         + '\n     }'
         + '\n'
 
+        + '\nfunction _normalizeEncoding(enc) {'
+        + '\n   if (!enc) return \'utf8\';'
+        + '\n   var retried;'
+        + '\n   while (true) {'
+        + '\n     switch (enc) {'
+        + '\n       case \'utf8\':'
+        + '\n       case \'utf-8\':'
+        + '\n         return \'utf8\';'
+        + '\n       case \'ucs2\':'
+        + '\n       case \'ucs-2\':'
+        + '\n       case \'utf16le\':'
+        + '\n       case \'utf-16le\':'
+        + '\n         return \'utf16le\';'
+        + '\n       case \'latin1\':'
+        + '\n       case \'binary\':'
+        + '\n         return \'latin1\';'
+        + '\n       case \'base64\':'
+        + '\n       case \'ascii\':'
+        + '\n       case \'hex\':'
+        + '\n         return enc;'
+        + '\n       default:'
+        + '\n         if (retried) return; // undefined'
+        + '\n         enc = (\'\' + enc).toLowerCase();'
+        + '\n         retried = true;'
+        + '\n     }'
+        + '\n   }'
+        + '\n };'
     ]
 
+
     // use custom Buffer.isEncoding reference
   , [
         /Buffer\.isEncoding\(/g
-      , 'isBufferEncoding\('
+      , 'isEncoding\('
     ]
 
-]
+    // use _normalizeEncoding everywhere
+  , [
+        /internalUtil\.normalizeEncoding/g
+      , '_normalizeEncoding'
+    ]
 
-module.exports['string_decoder.js'].out = 'index.js'
\ No newline at end of file
+]
diff --git a/build/package.json b/build/package.json
index f7ee6a4..29dc1c2 100644
--- a/build/package.json
+++ b/build/package.json
@@ -4,9 +4,20 @@
   "description": "",
   "main": "build.js",
   "dependencies": {
-    "bl": "~0.6.0",
-    "hyperzip": "0.0.0",
-    "hyperdirect": "0.0.0",
-    "cheerio": "~0.13.1"
+    "babel-core": "^6.5.2",
+    "babel-plugin-transform-es2015-arrow-functions": "^6.5.2",
+    "babel-plugin-transform-es2015-block-scoping": "^6.5.0",
+    "babel-plugin-transform-es2015-destructuring": "^6.18.0",
+    "babel-plugin-transform-es2015-for-of": "^6.8.0",
+    "babel-plugin-transform-es2015-parameters": "^6.11.4",
+    "babel-plugin-transform-es2015-shorthand-properties": "^6.8.0",
+    "babel-plugin-transform-es2015-template-literals": "^6.8.0",
+    "bl": "^1.2.0",
+    "glob": "^7.1.1",
+    "gunzip-maybe": "^1.4.0",
+    "hyperquest": "^2.1.2",
+    "pump": "^1.0.2",
+    "rimraf": "^2.6.1",
+    "tar-fs": "^1.15.1"
   }
 }
diff --git a/build/test-replacements.js b/build/test-replacements.js
index 5bbf602..f886f8b 100644
--- a/build/test-replacements.js
+++ b/build/test-replacements.js
@@ -21,4 +21,24 @@ module.exports['common.js'] = [
         /^                      global];$/m
       , '                      global].filter(Boolean);'
     ]
+
+  , [
+        /^/
+      , 'require(\'babel-polyfill\');'
+    ]
+
+  , [
+        /^(  for \(var x in global\) \{|function leakedGlobals\(\) \{)$/m
+      ,   '  /*<replacement>*/\n'
+        + '  if (typeof constructor == \'function\')\n'
+        + '    knownGlobals.push(constructor);\n'
+        + '  if (typeof DTRACE_NET_SOCKET_READ == \'function\')\n'
+        + '    knownGlobals.push(DTRACE_NET_SOCKET_READ);\n'
+        + '  if (typeof DTRACE_NET_SOCKET_WRITE == \'function\')\n'
+        + '    knownGlobals.push(DTRACE_NET_SOCKET_WRITE);\n'
+        + '  if (global.__coverage__)\n'
+        + '    knownGlobals.push(__coverage__);\n'
+        + '\'core,__core-js_shared__,Promise,Map,Set,WeakMap,WeakSet,Reflect,System,asap,Observable,regeneratorRuntime,_babelPolyfill\'.split(\',\').filter(function (item) {  return typeof global[item] !== undefined}).forEach(function (item) {knownGlobals.push(global[item])})'
+        + '  /*</replacement>*/\n\n$1'
+    ]
 ]
diff --git a/index.js b/index.js
deleted file mode 100644
index 2e44a03..0000000
--- a/index.js
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var Buffer = require('buffer').Buffer;
-
-var isBufferEncoding = Buffer.isEncoding
-  || function(encoding) {
-       switch (encoding && encoding.toLowerCase()) {
-         case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true;
-         default: return false;
-       }
-     }
-
-
-function assertEncoding(encoding) {
-  if (encoding && !isBufferEncoding(encoding)) {
-    throw new Error('Unknown encoding: ' + encoding);
-  }
-}
-
-var StringDecoder = exports.StringDecoder = function(encoding) {
-  this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
-  assertEncoding(encoding);
-  switch (this.encoding) {
-    case 'utf8':
-      // CESU-8 represents each of Surrogate Pair by 3-bytes
-      this.surrogateSize = 3;
-      break;
-    case 'ucs2':
-    case 'utf16le':
-      // UTF-16 represents each of Surrogate Pair by 2-bytes
-      this.surrogateSize = 2;
-      this.detectIncompleteChar = utf16DetectIncompleteChar;
-      break;
-    case 'base64':
-      // Base-64 stores 3 bytes in 4 chars, and pads the remainder.
-      this.surrogateSize = 3;
-      this.detectIncompleteChar = base64DetectIncompleteChar;
-      break;
-    default:
-      this.write = passThroughWrite;
-      return;
-  }
-
-  this.charBuffer = new Buffer(6);
-  this.charReceived = 0;
-  this.charLength = 0;
-};
-
-
-StringDecoder.prototype.write = function(buffer) {
-  var charStr = '';
-  var offset = 0;
-
-  // if our last write ended with an incomplete multibyte character
-  while (this.charLength) {
-    // determine how many remaining bytes this buffer has to offer for this char
-    var i = (buffer.length >= this.charLength - this.charReceived) ?
-                this.charLength - this.charReceived :
-                buffer.length;
-
-    // add the new bytes to the char buffer
-    buffer.copy(this.charBuffer, this.charReceived, offset, i);
-    this.charReceived += (i - offset);
-    offset = i;
-
-    if (this.charReceived < this.charLength) {
-      // still not enough chars in this buffer? wait for more ...
-      return '';
-    }
-
-    // get the character that was split
-    charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
-
-    // lead surrogate (D800-DBFF) is also the incomplete character
-    var charCode = charStr.charCodeAt(charStr.length - 1);
-    if (charCode >= 0xD800 && charCode <= 0xDBFF) {
-      this.charLength += this.surrogateSize;
-      charStr = '';
-      continue;
-    }
-    this.charReceived = this.charLength = 0;
-
-    // if there are no more bytes in this buffer, just emit our char
-    if (i == buffer.length) return charStr;
-
-    // otherwise cut off the characters end from the beginning of this buffer
-    buffer = buffer.slice(i, buffer.length);
-    break;
-  }
-
-  var lenIncomplete = this.detectIncompleteChar(buffer);
-
-  var end = buffer.length;
-  if (this.charLength) {
-    // buffer the incomplete character bytes we got
-    buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end);
-    this.charReceived = lenIncomplete;
-    end -= lenIncomplete;
-  }
-
-  charStr += buffer.toString(this.encoding, 0, end);
-
-  var end = charStr.length - 1;
-  var charCode = charStr.charCodeAt(end);
-  // lead surrogate (D800-DBFF) is also the incomplete character
-  if (charCode >= 0xD800 && charCode <= 0xDBFF) {
-    var size = this.surrogateSize;
-    this.charLength += size;
-    this.charReceived += size;
-    this.charBuffer.copy(this.charBuffer, size, 0, size);
-    this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding);
-    return charStr.substring(0, end);
-  }
-
-  // or just emit the charStr
-  return charStr;
-};
-
-StringDecoder.prototype.detectIncompleteChar = function(buffer) {
-  // determine how many bytes we have to check at the end of this buffer
-  var i = (buffer.length >= 3) ? 3 : buffer.length;
-
-  // Figure out if one of the last i bytes of our buffer announces an
-  // incomplete char.
-  for (; i > 0; i--) {
-    var c = buffer[buffer.length - i];
-
-    // See http://en.wikipedia.org/wiki/UTF-8#Description
-
-    // 110XXXXX
-    if (i == 1 && c >> 5 == 0x06) {
-      this.charLength = 2;
-      break;
-    }
-
-    // 1110XXXX
-    if (i <= 2 && c >> 4 == 0x0E) {
-      this.charLength = 3;
-      break;
-    }
-
-    // 11110XXX
-    if (i <= 3 && c >> 3 == 0x1E) {
-      this.charLength = 4;
-      break;
-    }
-  }
-
-  return i;
-};
-
-StringDecoder.prototype.end = function(buffer) {
-  var res = '';
-  if (buffer && buffer.length)
-    res = this.write(buffer);
-
-  if (this.charReceived) {
-    var cr = this.charReceived;
-    var buf = this.charBuffer;
-    var enc = this.encoding;
-    res += buf.slice(0, cr).toString(enc);
-  }
-
-  return res;
-};
-
-function passThroughWrite(buffer) {
-  return buffer.toString(this.encoding);
-}
-
-function utf16DetectIncompleteChar(buffer) {
-  var incomplete = this.charReceived = buffer.length % 2;
-  this.charLength = incomplete ? 2 : 0;
-  return incomplete;
-}
-
-function base64DetectIncompleteChar(buffer) {
-  var incomplete = this.charReceived = buffer.length % 3;
-  this.charLength = incomplete ? 3 : 0;
-  return incomplete;
-}
diff --git a/lib/string_decoder.js b/lib/string_decoder.js
new file mode 100644
index 0000000..6c598d2
--- /dev/null
+++ b/lib/string_decoder.js
@@ -0,0 +1,271 @@
+'use strict';
+
+var Buffer = require('buffer').Buffer;
+
+var isEncoding = Buffer.isEncoding || function (encoding) {
+  switch (encoding && encoding.toLowerCase()) {
+    case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':
+      return true;
+    default:
+      return false;
+  }
+};
+
+function _normalizeEncoding(enc) {
+  if (!enc) return 'utf8';
+  var retried;
+  while (true) {
+    switch (enc) {
+      case 'utf8':
+      case 'utf-8':
+        return 'utf8';
+      case 'ucs2':
+      case 'ucs-2':
+      case 'utf16le':
+      case 'utf-16le':
+        return 'utf16le';
+      case 'latin1':
+      case 'binary':
+        return 'latin1';
+      case 'base64':
+      case 'ascii':
+      case 'hex':
+        return enc;
+      default:
+        if (retried) return; // undefined
+        enc = ('' + enc).toLowerCase();
+        retried = true;
+    }
+  }
+};
+
+// Do not cache `Buffer.isEncoding` when checking encoding names as some
+// modules monkey-patch it to support additional encodings
+function normalizeEncoding(enc) {
+  var nenc = _normalizeEncoding(enc);
+  if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);
+  return nenc || enc;
+}
+
+// StringDecoder provides an interface for efficiently splitting a series of
+// buffers into a series of JS strings without breaking apart multi-byte
+// characters.
+exports.StringDecoder = StringDecoder;
+function StringDecoder(encoding) {
+  this.encoding = normalizeEncoding(encoding);
+  var nb;
+  switch (this.encoding) {
+    case 'utf16le':
+      this.text = utf16Text;
+      this.end = utf16End;
+      nb = 4;
+      break;
+    case 'utf8':
+      this.fillLast = utf8FillLast;
+      nb = 4;
+      break;
+    case 'base64':
+      this.text = base64Text;
+      this.end = base64End;
+      nb = 3;
+      break;
+    default:
+      this.write = simpleWrite;
+      this.end = simpleEnd;
+      return;
+  }
+  this.lastNeed = 0;
+  this.lastTotal = 0;
+  this.lastChar = Buffer.allocUnsafe(nb);
+}
+
+StringDecoder.prototype.write = function (buf) {
+  if (buf.length === 0) return '';
+  var r;
+  var i;
+  if (this.lastNeed) {
+    r = this.fillLast(buf);
+    if (r === undefined) return '';
+    i = this.lastNeed;
+    this.lastNeed = 0;
+  } else {
+    i = 0;
+  }
+  if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);
+  return r || '';
+};
+
+StringDecoder.prototype.end = utf8End;
+
+// Returns only complete characters in a Buffer
+StringDecoder.prototype.text = utf8Text;
+
+// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer
+StringDecoder.prototype.fillLast = function (buf) {
+  if (this.lastNeed <= buf.length) {
+    buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);
+    return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+  }
+  buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);
+  this.lastNeed -= buf.length;
+};
+
+// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a
+// continuation byte.
+function utf8CheckByte(byte) {
+  if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;
+  return -1;
+}
+
+// Checks at most 3 bytes at the end of a Buffer in order to detect an
+// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)
+// needed to complete the UTF-8 character (if applicable) are returned.
+function utf8CheckIncomplete(self, buf, i) {
+  var j = buf.length - 1;
+  if (j < i) return 0;
+  var nb = utf8CheckByte(buf[j]);
+  if (nb >= 0) {
+    if (nb > 0) self.lastNeed = nb - 1;
+    return nb;
+  }
+  if (--j < i) return 0;
+  nb = utf8CheckByte(buf[j]);
+  if (nb >= 0) {
+    if (nb > 0) self.lastNeed = nb - 2;
+    return nb;
+  }
+  if (--j < i) return 0;
+  nb = utf8CheckByte(buf[j]);
+  if (nb >= 0) {
+    if (nb > 0) {
+      if (nb === 2) nb = 0;else self.lastNeed = nb - 3;
+    }
+    return nb;
+  }
+  return 0;
+}
+
+// Validates as many continuation bytes for a multi-byte UTF-8 character as
+// needed or are available. If we see a non-continuation byte where we expect
+// one, we "replace" the validated continuation bytes we've seen so far with
+// UTF-8 replacement characters ('\ufffd'), to match v8's UTF-8 decoding
+// behavior. The continuation byte check is included three times in the case
+// where all of the continuation bytes for a character exist in the same buffer.
+// It is also done this way as a slight performance increase instead of using a
+// loop.
+function utf8CheckExtraBytes(self, buf, p) {
+  if ((buf[0] & 0xC0) !== 0x80) {
+    self.lastNeed = 0;
+    return '\ufffd'.repeat(p);
+  }
+  if (self.lastNeed > 1 && buf.length > 1) {
+    if ((buf[1] & 0xC0) !== 0x80) {
+      self.lastNeed = 1;
+      return '\ufffd'.repeat(p + 1);
+    }
+    if (self.lastNeed > 2 && buf.length > 2) {
+      if ((buf[2] & 0xC0) !== 0x80) {
+        self.lastNeed = 2;
+        return '\ufffd'.repeat(p + 2);
+      }
+    }
+  }
+}
+
+// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.
+function utf8FillLast(buf) {
+  var p = this.lastTotal - this.lastNeed;
+  var r = utf8CheckExtraBytes(this, buf, p);
+  if (r !== undefined) return r;
+  if (this.lastNeed <= buf.length) {
+    buf.copy(this.lastChar, p, 0, this.lastNeed);
+    return this.lastChar.toString(this.encoding, 0, this.lastTotal);
+  }
+  buf.copy(this.lastChar, p, 0, buf.length);
+  this.lastNeed -= buf.length;
+}
+
+// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a
+// partial character, the character's bytes are buffered until the required
+// number of bytes are available.
+function utf8Text(buf, i) {
+  var total = utf8CheckIncomplete(this, buf, i);
+  if (!this.lastNeed) return buf.toString('utf8', i);
+  this.lastTotal = total;
+  var end = buf.length - (total - this.lastNeed);
+  buf.copy(this.lastChar, 0, end);
+  return buf.toString('utf8', i, end);
+}
+
+// For UTF-8, a replacement character for each buffered byte of a (partial)
+// character needs to be added to the output.
+function utf8End(buf) {
+  var r = buf && buf.length ? this.write(buf) : '';
+  if (this.lastNeed) return r + '\ufffd'.repeat(this.lastTotal - this.lastNeed);
+  return r;
+}
+
+// UTF-16LE typically needs two bytes per character, but even if we have an even
+// number of bytes available, we need to check if we end on a leading/high
+// surrogate. In that case, we need to wait for the next two bytes in order to
+// decode the last character properly.
+function utf16Text(buf, i) {
+  if ((buf.length - i) % 2 === 0) {
+    var r = buf.toString('utf16le', i);
+    if (r) {
+      var c = r.charCodeAt(r.length - 1);
+      if (c >= 0xD800 && c <= 0xDBFF) {
+        this.lastNeed = 2;
+        this.lastTotal = 4;
+        this.lastChar[0] = buf[buf.length - 2];
+        this.lastChar[1] = buf[buf.length - 1];
+        return r.slice(0, -1);
+      }
+    }
+    return r;
+  }
+  this.lastNeed = 1;
+  this.lastTotal = 2;
+  this.lastChar[0] = buf[buf.length - 1];
+  return buf.toString('utf16le', i, buf.length - 1);
+}
+
+// For UTF-16LE we do not explicitly append special replacement characters if we
+// end on a partial character, we simply let v8 handle that.
+function utf16End(buf) {
+  var r = buf && buf.length ? this.write(buf) : '';
+  if (this.lastNeed) {
+    var end = this.lastTotal - this.lastNeed;
+    return r + this.lastChar.toString('utf16le', 0, end);
+  }
+  return r;
+}
+
+function base64Text(buf, i) {
+  var n = (buf.length - i) % 3;
+  if (n === 0) return buf.toString('base64', i);
+  this.lastNeed = 3 - n;
+  this.lastTotal = 3;
+  if (n === 1) {
+    this.lastChar[0] = buf[buf.length - 1];
+  } else {
+    this.lastChar[0] = buf[buf.length - 2];
+    this.lastChar[1] = buf[buf.length - 1];
+  }
+  return buf.toString('base64', i, buf.length - n);
+}
+
+function base64End(buf) {
+  var r = buf && buf.length ? this.write(buf) : '';
+  if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);
+  return r;
+}
+
+// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)
+function simpleWrite(buf) {
+  return buf.toString(this.encoding);
+}
+
+function simpleEnd(buf) {
+  return buf && buf.length ? this.write(buf) : '';
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 939a3cd..e1c2e54 100644
--- a/package.json
+++ b/package.json
@@ -2,13 +2,14 @@
   "name": "string_decoder",
   "version": "0.11.10-3",
   "description": "The string_decoder module from Node core",
-  "main": "index.js",
+  "main": "lib/string_decoder.js",
   "dependencies": {},
   "devDependencies": {
+    "babel-polyfill": "^6.23.0",
     "tap": "~0.4.8"
   },
   "scripts": {
-    "test": "tap test/simple/*.js"
+    "test": "tap test/parallel/*.js"
   },
   "repository": {
     "type": "git",
diff --git a/test/common.js b/test/common.js
index 9af8964..e879f8e 100644
--- a/test/common.js
+++ b/test/common.js
@@ -1,193 +1,384 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
+require('babel-polyfill'); /* eslint-disable required-modules */
+'use strict';
 var path = require('path');
+var fs = require('fs');
 var assert = require('assert');
+var os = require('os');
+var child_process = require('child_process');
+var stream = require('stream');
+var util = require('util');
+var Timer = process.binding('timer_wrap').Timer;
+var execSync = require('child_process').execSync;
+
+var testRoot = process.env.NODE_TEST_DIR ? fs.realpathSync(process.env.NODE_TEST_DIR) : __dirname;
 
-exports.testDir = path.dirname(__filename);
-exports.fixturesDir = path.join(exports.testDir, 'fixtures');
-exports.libDir = path.join(exports.testDir, '../lib');
-exports.tmpDir = path.join(exports.testDir, 'tmp');
+exports.fixturesDir = path.join(__dirname, 'fixtures');
+exports.tmpDirName = 'tmp';
+// PORT should match the definition in test/testpy/__init__.py.
 exports.PORT = +process.env.NODE_COMMON_PORT || 12346;
+exports.isWindows = process.platform === 'win32';
+exports.isWOW64 = exports.isWindows && process.env.PROCESSOR_ARCHITEW6432 !== undefined;
+exports.isAix = process.platform === 'aix';
+exports.isLinuxPPCBE = process.platform === 'linux' && process.arch === 'ppc64' && os.endianness() === 'BE';
+exports.isSunOS = process.platform === 'sunos';
+exports.isFreeBSD = process.platform === 'freebsd';
+exports.isLinux = process.platform === 'linux';
+exports.isOSX = process.platform === 'darwin';
+
+exports.enoughTestMem = os.totalmem() > 0x40000000; /* 1 Gb */
+
+var cpus = os.cpus();
+exports.enoughTestCpu = Array.isArray(cpus) && (cpus.length > 1 || cpus[0].speed > 999);
+
+exports.rootDir = exports.isWindows ? 'c:\\' : '/';
+exports.buildType = process.config.target_defaults.default_configuration;
+
+function rimrafSync(p) {
+  var st = void 0;
+  try {
+    st = fs.lstatSync(p);
+  } catch (e) {
+    if (e.code === 'ENOENT') return;
+  }
+
+  try {
+    if (st && st.isDirectory()) rmdirSync(p, null);else fs.unlinkSync(p);
+  } catch (e) {
+    if (e.code === 'ENOENT') return;
+    if (e.code === 'EPERM') return rmdirSync(p, e);
+    if (e.code !== 'EISDIR') throw e;
+    rmdirSync(p, e);
+  }
+}
+
+function rmdirSync(p, originalEr) {
+  try {
+    fs.rmdirSync(p);
+  } catch (e) {
+    if (e.code === 'ENOTDIR') throw originalEr;
+    if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') {
+      var enc = exports.isLinux ? 'buffer' : 'utf8';
+      fs.readdirSync(p, enc).forEach(function (f) {
+        if (f instanceof Buffer) {
+          var buf = Buffer.concat([Buffer.from(p), Buffer.from(path.sep), f]);
+          rimrafSync(buf);
+        } else {
+          rimrafSync(path.join(p, f));
+        }
+      });
+      fs.rmdirSync(p);
+    }
+  }
+}
+
+exports.refreshTmpDir = function () {
+  rimrafSync(exports.tmpDir);
+  fs.mkdirSync(exports.tmpDir);
+};
+
+if (process.env.TEST_THREAD_ID) {
+  exports.PORT += process.env.TEST_THREAD_ID * 100;
+  exports.tmpDirName += '.' + process.env.TEST_THREAD_ID;
+}
+exports.tmpDir = path.join(testRoot, exports.tmpDirName);
+
+var opensslCli = null;
+var inFreeBSDJail = null;
+var localhostIPv4 = null;
+
+exports.localIPv6Hosts = ['localhost'];
+if (exports.isLinux) {
+  exports.localIPv6Hosts = [
+  // Debian/Ubuntu
+  'ip6-localhost', 'ip6-loopback',
+
+  // SUSE
+  'ipv6-localhost', 'ipv6-loopback',
+
+  // Typically universal
+  'localhost'];
+}
+
+Object.defineProperty(exports, 'inFreeBSDJail', {
+  get: function () {
+    if (inFreeBSDJail !== null) return inFreeBSDJail;
+
+    if (exports.isFreeBSD && child_process.execSync('sysctl -n security.jail.jailed').toString() === '1\n') {
+      inFreeBSDJail = true;
+    } else {
+      inFreeBSDJail = false;
+    }
+    return inFreeBSDJail;
+  }
+});
+
+Object.defineProperty(exports, 'localhostIPv4', {
+  get: function () {
+    if (localhostIPv4 !== null) return localhostIPv4;
+
+    if (exports.inFreeBSDJail) {
+      // Jailed network interfaces are a bit special - since we need to jump
+      // through loops, as well as this being an exception case, assume the
+      // user will provide this instead.
+      if (process.env.LOCALHOST) {
+        localhostIPv4 = process.env.LOCALHOST;
+      } else {
+        console.error('Looks like we\'re in a FreeBSD Jail. ' + 'Please provide your default interface address ' + 'as LOCALHOST or expect some tests to fail.');
+      }
+    }
+
+    if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
+
+    return localhostIPv4;
+  }
+});
+
+// opensslCli defined lazily to reduce overhead of spawnSync
+Object.defineProperty(exports, 'opensslCli', { get: function () {
+    if (opensslCli !== null) return opensslCli;
+
+    if (process.config.variables.node_shared_openssl) {
+      // use external command
+      opensslCli = 'openssl';
+    } else {
+      // use command built from sources included in Node.js repository
+      opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli');
+    }
 
-if (process.platform === 'win32') {
+    if (exports.isWindows) opensslCli += '.exe';
+
+    var opensslCmd = child_process.spawnSync(opensslCli, ['version']);
+    if (opensslCmd.status !== 0 || opensslCmd.error !== undefined) {
+      // openssl command cannot be executed
+      opensslCli = false;
+    }
+    return opensslCli;
+  }, enumerable: true });
+
+Object.defineProperty(exports, 'hasCrypto', {
+  get: function () {
+    return process.versions.openssl ? true : false;
+  }
+});
+
+Object.defineProperty(exports, 'hasFipsCrypto', {
+  get: function () {
+    return exports.hasCrypto && require('crypto').fips;
+  }
+});
+
+if (exports.isWindows) {
   exports.PIPE = '\\\\.\\pipe\\libuv-test';
-  exports.opensslCli = path.join(process.execPath, '..', 'openssl-cli.exe');
+  if (process.env.TEST_THREAD_ID) {
+    exports.PIPE += '.' + process.env.TEST_THREAD_ID;
+  }
 } else {
   exports.PIPE = exports.tmpDir + '/test.sock';
-  exports.opensslCli = path.join(process.execPath, '..', 'openssl-cli');
 }
 
-var util = require('util');
-for (var i in util) exports[i] = util[i];
-//for (var i in exports) global[i] = exports[i];
-
-function protoCtrChain(o) {
-  var result = [];
-  for (; o; o = o.__proto__) { result.push(o.constructor); }
-  return result.join();
-}
+var ifaces = os.networkInterfaces();
+exports.hasIPv6 = Object.keys(ifaces).some(function (name) {
+  return (/lo/.test(name) && ifaces[name].some(function (info) {
+      return info.family === 'IPv6';
+    })
+  );
+});
 
-exports.indirectInstanceOf = function(obj, cls) {
-  if (obj instanceof cls) { return true; }
-  var clsChain = protoCtrChain(cls.prototype);
-  var objChain = protoCtrChain(obj);
-  return objChain.slice(-clsChain.length) === clsChain;
+/*
+ * Check that when running a test with
+ * `$node --abort-on-uncaught-exception $file child`
+ * the process aborts.
+ */
+exports.childShouldThrowAndAbort = function () {
+  var testCmd = '';
+  if (!exports.isWindows) {
+    // Do not create core files, as it can take a lot of disk space on
+    // continuous testing and developers' machines
+    testCmd += 'ulimit -c 0 && ';
+  }
+  testCmd += process.argv[0] + ' --abort-on-uncaught-exception ';
+  testCmd += process.argv[1] + ' child';
+  var child = child_process.exec(testCmd);
+  child.on('exit', function onExit(exitCode, signal) {
+    var errMsg = 'Test should have aborted ' + ('but instead exited with exit code ' + exitCode) + (' and signal ' + signal);
+    assert(exports.nodeProcessAborted(exitCode, signal), errMsg);
+  });
 };
 
-
-exports.ddCommand = function(filename, kilobytes) {
-  if (process.platform === 'win32') {
+exports.ddCommand = function (filename, kilobytes) {
+  if (exports.isWindows) {
     var p = path.resolve(exports.fixturesDir, 'create-file.js');
-    return '"' + process.argv[0] + '" "' + p + '" "' +
-           filename + '" ' + (kilobytes * 1024);
+    return '"' + process.argv[0] + '" "' + p + '" "' + filename + '" ' + kilobytes * 1024;
   } else {
     return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes;
   }
 };
 
-
-exports.spawnCat = function(options) {
+exports.spawnPwd = function (options) {
   var spawn = require('child_process').spawn;
 
-  if (process.platform === 'win32') {
-    return spawn('more', [], options);
+  if (exports.isWindows) {
+    return spawn('cmd.exe', ['/d', '/c', 'cd'], options);
   } else {
-    return spawn('cat', [], options);
+    return spawn('pwd', [], options);
   }
 };
 
+exports.spawnSyncPwd = function (options) {
+  var spawnSync = require('child_process').spawnSync;
 
-exports.spawnPwd = function(options) {
-  var spawn = require('child_process').spawn;
-
-  if (process.platform === 'win32') {
-    return spawn('cmd.exe', ['/c', 'cd'], options);
+  if (exports.isWindows) {
+    return spawnSync('cmd.exe', ['/d', '/c', 'cd'], options);
   } else {
-    return spawn('pwd', [], options);
+    return spawnSync('pwd', [], options);
   }
 };
 
+exports.platformTimeout = function (ms) {
+  if (process.config.target_defaults.default_configuration === 'Debug') ms = 2 * ms;
+
+  if (global.__coverage__) ms = 4 * ms;
+
+  if (exports.isAix) return 2 * ms; // default localhost speed is slower on AIX
+
+  if (process.arch !== 'arm') return ms;
+
+  var armv = process.config.variables.arm_version;
+
+  if (armv === '6') return 7 * ms; // ARMv6
+
+  if (armv === '7') return 2 * ms; // ARMv7
+
+  return ms; // ARMv8+
+};
+
+var knownGlobals = [Buffer, clearImmediate, clearInterval, clearTimeout, console, constructor, // Enumerable in V8 3.21.
+global, process, setImmediate, setInterval, setTimeout];
+
+if (global.gc) {
+  knownGlobals.push(global.gc);
+}
+
+if (global.DTRACE_HTTP_SERVER_RESPONSE) {
+  knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
+  knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
+  knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
+  knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
+  knownGlobals.push(DTRACE_NET_STREAM_END);
+  knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
+}
+
+if (global.COUNTER_NET_SERVER_CONNECTION) {
+  knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
+  knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
+  knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
+  knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
+  knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
+  knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
+}
+
+if (global.LTTNG_HTTP_SERVER_RESPONSE) {
+  knownGlobals.push(LTTNG_HTTP_SERVER_RESPONSE);
+  knownGlobals.push(LTTNG_HTTP_SERVER_REQUEST);
+  knownGlobals.push(LTTNG_HTTP_CLIENT_RESPONSE);
+  knownGlobals.push(LTTNG_HTTP_CLIENT_REQUEST);
+  knownGlobals.push(LTTNG_NET_STREAM_END);
+  knownGlobals.push(LTTNG_NET_SERVER_CONNECTION);
+}
+
+if (global.ArrayBuffer) {
+  knownGlobals.push(ArrayBuffer);
+  knownGlobals.push(Int8Array);
+  knownGlobals.push(Uint8Array);
+  knownGlobals.push(Uint8ClampedArray);
+  knownGlobals.push(Int16Array);
+  knownGlobals.push(Uint16Array);
+  knownGlobals.push(Int32Array);
+  knownGlobals.push(Uint32Array);
+  knownGlobals.push(Float32Array);
+  knownGlobals.push(Float64Array);
+  knownGlobals.push(DataView);
+}
+
+// Harmony features.
+if (global.Proxy) {
+  knownGlobals.push(Proxy);
+}
+
+if (global.Symbol) {
+  knownGlobals.push(Symbol);
+}
+
+function allowGlobals() {
+  for (var _len = arguments.length, whitelist = Array(_len), _key = 0; _key < _len; _key++) {
+    whitelist[_key] = arguments[_key];
+  }
+
+  knownGlobals = knownGlobals.concat(whitelist);
+}
+exports.allowGlobals = allowGlobals;
+
+/*<replacement>*/
+if (typeof constructor == 'function') knownGlobals.push(constructor);
+if (typeof DTRACE_NET_SOCKET_READ == 'function') knownGlobals.push(DTRACE_NET_SOCKET_READ);
+if (typeof DTRACE_NET_SOCKET_WRITE == 'function') knownGlobals.push(DTRACE_NET_SOCKET_WRITE);
+if (global.__coverage__) knownGlobals.push(__coverage__);
+'core,__core-js_shared__,Promise,Map,Set,WeakMap,WeakSet,Reflect,System,asap,Observable,regeneratorRuntime,_babelPolyfill'.split(',').filter(function (item) {
+  return typeof global[item] !== undefined;
+}).forEach(function (item) {
+  knownGlobals.push(global[item]);
+}); /*</replacement>*/
+
+function leakedGlobals() {
+  var leaked = [];
+
+  for (var val in global) {
+    if (!knownGlobals.includes(global[val])) leaked.push(val);
+  }if (global.__coverage__) {
+    return leaked.filter(function (varname) {
+      return !/^(cov_|__cov)/.test(varname);
+    });
+  } else {
+    return leaked;
+  }
+}
+exports.leakedGlobals = leakedGlobals;
 
 // Turn this off if the test should not check for global leaks.
 exports.globalCheck = true;
 
-process.on('exit', function() {
+process.on('exit', function () {
   if (!exports.globalCheck) return;
-  var knownGlobals = [setTimeout,
-                      setInterval,
-                      typeof setImmediate == 'undefined' ? null : setImmediate,
-                      clearTimeout,
-                      clearInterval,
-                      typeof clearImmediate == 'undefined' ? null : clearImmediate,
-                      console,
-                      constructor, // Enumerable in V8 3.21.
-                      Buffer,
-                      process,
-                      global].filter(Boolean);
-
-  if (global.gc) {
-    knownGlobals.push(gc);
-  }
-
-  if (global.DTRACE_HTTP_SERVER_RESPONSE) {
-    knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
-    knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
-    knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
-    knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
-    knownGlobals.push(DTRACE_NET_STREAM_END);
-    knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
-    knownGlobals.push(DTRACE_NET_SOCKET_READ);
-    knownGlobals.push(DTRACE_NET_SOCKET_WRITE);
-  }
-  if (global.COUNTER_NET_SERVER_CONNECTION) {
-    knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
-    knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
-    knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
-    knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
-    knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
-    knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
-  }
-
-  if (global.ArrayBuffer) {
-    knownGlobals.push(ArrayBuffer);
-    knownGlobals.push(Int8Array);
-    knownGlobals.push(Uint8Array);
-    knownGlobals.push(Uint8ClampedArray);
-    knownGlobals.push(Int16Array);
-    knownGlobals.push(Uint16Array);
-    knownGlobals.push(Int32Array);
-    knownGlobals.push(Uint32Array);
-    knownGlobals.push(Float32Array);
-    knownGlobals.push(Float64Array);
-    knownGlobals.push(DataView);
-  }
-
-  for (var x in global) {
-    var found = false;
-
-    for (var y in knownGlobals) {
-      if (global[x] === knownGlobals[y]) {
-        found = true;
-        break;
-      }
-    }
-
-    if (!found) {
-      console.error('Unknown global: %s', x);
-      assert.ok(false, 'Unknown global found');
-    }
+  var leaked = leakedGlobals();
+  if (leaked.length > 0) {
+    fail('Unexpected global(s) found: ' + leaked.join(', '));
   }
 });
 
-
 var mustCallChecks = [];
 
-
 function runCallChecks(exitCode) {
   if (exitCode !== 0) return;
 
-  var failed = mustCallChecks.filter(function(context) {
+  var failed = mustCallChecks.filter(function (context) {
     return context.actual !== context.expected;
   });
 
-  failed.forEach(function(context) {
-    console.log('Mismatched %s function calls. Expected %d, actual %d.',
-                context.name,
-                context.expected,
-                context.actual);
+  failed.forEach(function (context) {
+    console.log('Mismatched %s function calls. Expected %d, actual %d.', context.name, context.expected, context.actual);
     console.log(context.stack.split('\n').slice(2).join('\n'));
   });
 
   if (failed.length) process.exit(1);
 }
 
-
-exports.mustCall = function(fn, expected) {
-  if (typeof expected !== 'number') expected = 1;
+exports.mustCall = function (fn, expected) {
+  if (expected === undefined) expected = 1;else if (typeof expected !== 'number') throw new TypeError('Invalid expected value: ' + expected);
 
   var context = {
     expected: expected,
     actual: 0,
-    stack: (new Error).stack,
+    stack: new Error().stack,
     name: fn.name || '<anonymous>'
   };
 
@@ -196,8 +387,197 @@ exports.mustCall = function(fn, expected) {
 
   mustCallChecks.push(context);
 
-  return function() {
+  return function () {
     context.actual++;
     return fn.apply(this, arguments);
   };
 };
+
+exports.hasMultiLocalhost = function hasMultiLocalhost() {
+  var TCP = process.binding('tcp_wrap').TCP;
+  var t = new TCP();
+  var ret = t.bind('127.0.0.2', exports.PORT);
+  t.close();
+  return ret === 0;
+};
+
+exports.fileExists = function (pathname) {
+  try {
+    fs.accessSync(pathname);
+    return true;
+  } catch (err) {
+    return false;
+  }
+};
+
+exports.canCreateSymLink = function () {
+  // On Windows, creating symlinks requires admin privileges.
+  // We'll only try to run symlink test if we have enough privileges.
+  // On other platforms, creating symlinks shouldn't need admin privileges
+  if (exports.isWindows) {
+    // whoami.exe needs to be the one from System32
+    // If unix tools are in the path, they can shadow the one we want,
+    // so use the full path while executing whoami
+    var whoamiPath = path.join(process.env['SystemRoot'], 'System32', 'whoami.exe');
+
+    var err = false;
+    var output = '';
+
+    try {
+      output = execSync(whoamiPath + ' /priv', { timout: 1000 });
+    } catch (e) {
+      err = true;
+    } finally {
+      if (err || !output.includes('SeCreateSymbolicLinkPrivilege')) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+};
+
+function fail(msg) {
+  assert.fail(null, null, msg);
+}
+exports.fail = fail;
+
+exports.mustNotCall = function (msg) {
+  return function mustNotCall() {
+    fail(msg || 'function should not have been called');
+  };
+};
+
+exports.skip = function (msg) {
+  console.log('1..0 # Skipped: ' + msg);
+};
+
+// A stream to push an array into a REPL
+function ArrayStream() {
+  this.run = function (data) {
+    var _this = this;
+
+    data.forEach(function (line) {
+      _this.emit('data', line + '\n');
+    });
+  };
+}
+
+util.inherits(ArrayStream, stream.Stream);
+exports.ArrayStream = ArrayStream;
+ArrayStream.prototype.readable = true;
+ArrayStream.prototype.writable = true;
+ArrayStream.prototype.pause = function () {};
+ArrayStream.prototype.resume = function () {};
+ArrayStream.prototype.write = function () {};
+
+// Returns true if the exit code "exitCode" and/or signal name "signal"
+// represent the exit code and/or signal name of a node process that aborted,
+// false otherwise.
+exports.nodeProcessAborted = function nodeProcessAborted(exitCode, signal) {
+  // Depending on the compiler used, node will exit with either
+  // exit code 132 (SIGILL), 133 (SIGTRAP) or 134 (SIGABRT).
+  var expectedExitCodes = [132, 133, 134];
+
+  // On platforms using KSH as the default shell (like SmartOS),
+  // when a process aborts, KSH exits with an exit code that is
+  // greater than 256, and thus the exit code emitted with the 'exit'
+  // event is null and the signal is set to either SIGILL, SIGTRAP,
+  // or SIGABRT (depending on the compiler).
+  var expectedSignals = ['SIGILL', 'SIGTRAP', 'SIGABRT'];
+
+  // On Windows, v8's base::OS::Abort triggers an access violation,
+  // which corresponds to exit code 3221225477 (0xC0000005)
+  if (exports.isWindows) expectedExitCodes = [3221225477];
+
+  // When using --abort-on-uncaught-exception, V8 will use
+  // base::OS::Abort to terminate the process.
+  // Depending on the compiler used, the shell or other aspects of
+  // the platform used to build the node binary, this will actually
+  // make V8 exit by aborting or by raising a signal. In any case,
+  // one of them (exit code or signal) needs to be set to one of
+  // the expected exit codes or signals.
+  if (signal !== null) {
+    return expectedSignals.includes(signal);
+  } else {
+    return expectedExitCodes.includes(exitCode);
+  }
+};
+
+exports.busyLoop = function busyLoop(time) {
+  var startTime = Timer.now();
+  var stopTime = startTime + time;
+  while (Timer.now() < stopTime) {}
+};
+
+exports.isAlive = function isAlive(pid) {
+  try {
+    process.kill(pid, 'SIGCONT');
+    return true;
+  } catch (e) {
+    return false;
+  }
+};
+
+exports.expectWarning = function (name, expected) {
+  if (typeof expected === 'string') expected = [expected];
+  process.on('warning', exports.mustCall(function (warning) {
+    assert.strictEqual(warning.name, name);
+    assert.ok(expected.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));
+};
+
+Object.defineProperty(exports, 'hasIntl', {
+  get: function () {
+    return process.binding('config').hasIntl;
+  }
+});
+
+// https://github.com/w3c/testharness.js/blob/master/testharness.js
+exports.WPT = {
+  test: function (fn, desc) {
+    try {
+      fn();
+    } catch (err) {
+      if (err instanceof Error) err.message = 'In ' + desc + ':\n  ' + err.message;
+      throw err;
+    }
+  },
+  assert_equals: assert.strictEqual,
+  assert_true: function (value, message) {
+    return assert.strictEqual(value, true, message);
+  },
+  assert_false: function (value, message) {
+    return assert.strictEqual(value, false, message);
+  },
+  assert_throws: function (code, func, desc) {
+    assert.throws(func, function (err) {
+      return typeof err === 'object' && 'name' in err && err.name === code.name;
+    }, desc);
+  },
+  assert_array_equals: assert.deepStrictEqual,
+  assert_unreached: function (desc) {
+    assert.fail(undefined, undefined, 'Reached unreachable code: ' + desc);
+  }
+};
+
+// Useful for testing expected internal/error objects
+exports.expectsError = function expectsError(_ref) {
+  var code = _ref.code,
+      type = _ref.type,
+      message = _ref.message;
+
+  return function (error) {
+    assert.strictEqual(error.code, code);
+    if (type !== undefined) assert(error instanceof type, error + ' is not the expected type ' + type);
+    if (message instanceof RegExp) {
+      assert(message.test(error.message), error.message + ' does not match ' + message);
+    } else if (typeof message === 'string') {
+      assert.strictEqual(error.message, message);
+    }
+    return true;
+  };
+};
\ No newline at end of file
diff --git a/test/parallel/test-string-decoder-end.js b/test/parallel/test-string-decoder-end.js
new file mode 100644
index 0000000..0031adf
--- /dev/null
+++ b/test/parallel/test-string-decoder-end.js
@@ -0,0 +1,58 @@
+'use strict';
+// verify that the string decoder works getting 1 byte at a time,
+// the whole buffer at once, and that both match the .toString(enc)
+// result of the entire buffer.
+
+require('../common');
+var assert = require('assert');
+var SD = require('../../').StringDecoder;
+var encodings = ['base64', 'hex', 'utf8', 'utf16le', 'ucs2'];
+
+var bufs = ['☃💩', 'asdf'].map(function (b) {
+  return Buffer.from(b);
+});
+
+// also test just arbitrary bytes from 0-15.
+for (var i = 1; i <= 16; i++) {
+  var bytes = '.'.repeat(i - 1).split('.').map(function (_, j) {
+    return j + 0x78;
+  });
+  bufs.push(Buffer.from(bytes));
+}
+
+encodings.forEach(testEncoding);
+
+console.log('ok');
+
+function testEncoding(encoding) {
+  bufs.forEach(function (buf) {
+    testBuf(encoding, buf);
+  });
+}
+
+function testBuf(encoding, buf) {
+  console.error('# %s', encoding, buf);
+
+  // write one byte at a time.
+  var s = new SD(encoding);
+  var res1 = '';
+  for (var _i = 0; _i < buf.length; _i++) {
+    res1 += s.write(buf.slice(_i, _i + 1));
+  }
+  res1 += s.end();
+
+  // write the whole buffer at once.
+  var res2 = '';
+  s = new SD(encoding);
+  res2 += s.write(buf);
+  res2 += s.end();
+
+  // .toString() on the buffer
+  var res3 = buf.toString(encoding);
+
+  console.log('expect=%j', res3);
+  console.log('res1=%j', res1);
+  console.log('res2=%j', res2);
+  assert.strictEqual(res1, res3, 'one byte at a time should match toString');
+  assert.strictEqual(res2, res3, 'all bytes at once should match toString');
+}
\ No newline at end of file
diff --git a/test/parallel/test-string-decoder.js b/test/parallel/test-string-decoder.js
new file mode 100644
index 0000000..9345e03
--- /dev/null
+++ b/test/parallel/test-string-decoder.js
@@ -0,0 +1,174 @@
+'use strict';
+
+require('../common');
+var assert = require('assert');
+var inspect = require('util').inspect;
+var StringDecoder = require('../../').StringDecoder;
+
+// Test default encoding
+var decoder = new StringDecoder();
+assert.strictEqual(decoder.encoding, 'utf8');
+
+process.stdout.write('scanning ');
+
+// UTF-8
+test('utf-8', Buffer.from('$', 'utf-8'), '$');
+test('utf-8', Buffer.from('¢', 'utf-8'), '¢');
+test('utf-8', Buffer.from('€', 'utf-8'), '€');
+test('utf-8', Buffer.from('𤭢', 'utf-8'), '𤭢');
+// A mixed ascii and non-ascii string
+// Test stolen from deps/v8/test/cctest/test-strings.cc
+// U+02E4 -> CB A4
+// U+0064 -> 64
+// U+12E4 -> E1 8B A4
+// U+0030 -> 30
+// U+3045 -> E3 81 85
+test('utf-8', Buffer.from([0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 0x30, 0xE3, 0x81, 0x85]), '\u02e4\u0064\u12e4\u0030\u3045');
+
+// Some invalid input, known to have caused trouble with chunking
+// in https://github.com/nodejs/node/pull/7310#issuecomment-226445923
+// 00: |00000000 ASCII
+// 41: |01000001 ASCII
+// B8: 10|111000 continuation
+// CC: 110|01100 two-byte head
+// E2: 1110|0010 three-byte head
+// F0: 11110|000 four-byte head
+// F1: 11110|001'another four-byte head
+// FB: 111110|11 "five-byte head", not UTF-8
+test('utf-8', Buffer.from('C9B5A941', 'hex'), '\u0275\ufffdA');
+test('utf-8', Buffer.from('E2', 'hex'), '\ufffd');
+test('utf-8', Buffer.from('E241', 'hex'), '\ufffdA');
+test('utf-8', Buffer.from('CCCCB8', 'hex'), '\ufffd\u0338');
+test('utf-8', Buffer.from('F0B841', 'hex'), '\ufffd\ufffdA');
+test('utf-8', Buffer.from('F1CCB8', 'hex'), '\ufffd\u0338');
+test('utf-8', Buffer.from('F0FB00', 'hex'), '\ufffd\ufffd\0');
+test('utf-8', Buffer.from('CCE2B8B8', 'hex'), '\ufffd\u2e38');
+test('utf-8', Buffer.from('E2B8CCB8', 'hex'), '\ufffd\ufffd\u0338');
+test('utf-8', Buffer.from('E2FBCC01', 'hex'), '\ufffd\ufffd\ufffd\u0001');
+test('utf-8', Buffer.from('EDA0B5EDB08D', 'hex'), // CESU-8 of U+1D40D
+'\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd');
+test('utf-8', Buffer.from('CCB8CDB9', 'hex'), '\u0338\u0379');
+
+// UCS-2
+test('ucs2', Buffer.from('ababc', 'ucs2'), 'ababc');
+
+// UTF-16LE
+test('utf16le', Buffer.from('3DD84DDC', 'hex'), '\ud83d\udc4d'); // thumbs up
+
+console.log(' crayon!');
+
+// Additional UTF-8 tests
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('E1', 'hex')), '');
+assert.strictEqual(decoder.end(), '\ufffd');
+
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('E18B', 'hex')), '');
+assert.strictEqual(decoder.end(), '\ufffd\ufffd');
+
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('\ufffd')), '\ufffd');
+assert.strictEqual(decoder.end(), '');
+
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('\ufffd\ufffd\ufffd')), '\ufffd\ufffd\ufffd');
+assert.strictEqual(decoder.end(), '');
+
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('EFBFBDE2', 'hex')), '\ufffd');
+assert.strictEqual(decoder.end(), '\ufffd');
+
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.write(Buffer.from('F1', 'hex')), '');
+assert.strictEqual(decoder.write(Buffer.from('41F2', 'hex')), '\ufffdA');
+assert.strictEqual(decoder.end(), '\ufffd');
+
+// Additional utf8Text test
+decoder = new StringDecoder('utf8');
+assert.strictEqual(decoder.text(Buffer.from([0x41]), 2), '');
+
+// Additional UTF-16LE surrogate pair tests
+decoder = new StringDecoder('utf16le');
+assert.strictEqual(decoder.write(Buffer.from('3DD8', 'hex')), '');
+assert.strictEqual(decoder.write(Buffer.from('4D', 'hex')), '');
+assert.strictEqual(decoder.write(Buffer.from('DC', 'hex')), '\ud83d\udc4d');
+assert.strictEqual(decoder.end(), '');
+
+decoder = new StringDecoder('utf16le');
+assert.strictEqual(decoder.write(Buffer.from('3DD8', 'hex')), '');
+assert.strictEqual(decoder.end(), '\ud83d');
+
+decoder = new StringDecoder('utf16le');
+assert.strictEqual(decoder.write(Buffer.from('3DD8', 'hex')), '');
+assert.strictEqual(decoder.write(Buffer.from('4D', 'hex')), '');
+assert.strictEqual(decoder.end(), '\ud83d');
+
+assert.throws(function () {
+  new StringDecoder(1);
+}, /^Error: Unknown encoding: 1$/);
+
+assert.throws(function () {
+  new StringDecoder('test');
+}, /^Error: Unknown encoding: test$/);
+
+// test verifies that StringDecoder will correctly decode the given input
+// buffer with the given encoding to the expected output. It will attempt all
+// possible ways to write() the input buffer, see writeSequences(). The
+// singleSequence allows for easy debugging of a specific sequence which is
+// useful in case of test failures.
+function test(encoding, input, expected, singleSequence) {
+  var sequences = void 0;
+  if (!singleSequence) {
+    sequences = writeSequences(input.length);
+  } else {
+    sequences = [singleSequence];
+  }
+  sequences.forEach(function (sequence) {
+    var decoder = new StringDecoder(encoding);
+    var output = '';
+    sequence.forEach(function (write) {
+      output += decoder.write(input.slice(write[0], write[1]));
+    });
+    output += decoder.end();
+    process.stdout.write('.');
+    if (output !== expected) {
+      var message = 'Expected "' + unicodeEscape(expected) + '", ' + 'but got "' + unicodeEscape(output) + '"\n' + 'input: ' + input.toString('hex').match(/.{2}/g) + '\n' + 'Write sequence: ' + JSON.stringify(sequence) + '\n' + 'Full Decoder State: ' + inspect(decoder);
+      assert.fail(output, expected, message);
+    }
+  });
+}
+
+// unicodeEscape prints the str contents as unicode escape codes.
+function unicodeEscape(str) {
+  var r = '';
+  for (var i = 0; i < str.length; i++) {
+    r += '\\u' + str.charCodeAt(i).toString(16);
+  }
+  return r;
+}
+
+// writeSequences returns an array of arrays that describes all possible ways a
+// buffer of the given length could be split up and passed to sequential write
+// calls.
+//
+// e.G. writeSequences(3) will return: [
+//   [ [ 0, 3 ] ],
+//   [ [ 0, 2 ], [ 2, 3 ] ],
+//   [ [ 0, 1 ], [ 1, 3 ] ],
+//   [ [ 0, 1 ], [ 1, 2 ], [ 2, 3 ] ]
+// ]
+function writeSequences(length, start, sequence) {
+  if (start === undefined) {
+    start = 0;
+    sequence = [];
+  } else if (start === length) {
+    return [sequence];
+  }
+  var sequences = [];
+  for (var end = length; end > start; end--) {
+    var subSequence = sequence.concat([[start, end]]);
+    var subSequences = writeSequences(length, end, subSequence, sequences);
+    sequences = sequences.concat(subSequences);
+  }
+  return sequences;
+}
\ No newline at end of file
diff --git a/test/simple/test-string-decoder-end.js b/test/simple/test-string-decoder-end.js
deleted file mode 100644
index 869a411..0000000
--- a/test/simple/test-string-decoder-end.js
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// verify that the string decoder works getting 1 byte at a time,
-// the whole buffer at once, and that both match the .toString(enc)
-// result of the entire buffer.
-
-var assert = require('assert');
-var SD = require('../../').StringDecoder;
-var encodings = ['base64', 'hex', 'utf8', 'utf16le', 'ucs2'];
-
-var bufs = [ '☃💩', 'asdf' ].map(function(b) {
-  return new Buffer(b);
-});
-
-// also test just arbitrary bytes from 0-15.
-for (var i = 1; i <= 16; i++) {
-  var bytes = new Array(i).join('.').split('.').map(function(_, j) {
-    return j + 0x78;
-  });
-  bufs.push(new Buffer(bytes));
-}
-
-encodings.forEach(testEncoding);
-
-console.log('ok');
-
-function testEncoding(encoding) {
-  bufs.forEach(function(buf) {
-    testBuf(encoding, buf);
-  });
-}
-
-function testBuf(encoding, buf) {
-  console.error('# %s', encoding, buf);
-
-  // write one byte at a time.
-  var s = new SD(encoding);
-  var res1 = '';
-  for (var i = 0; i < buf.length; i++) {
-    res1 += s.write(buf.slice(i, i + 1));
-  }
-  res1 += s.end();
-
-  // write the whole buffer at once.
-  var res2 = '';
-  var s = new SD(encoding);
-  res2 += s.write(buf);
-  res2 += s.end();
-
-  // .toString() on the buffer
-  var res3 = buf.toString(encoding);
-
-  console.log('expect=%j', res3);
-  assert.equal(res1, res3, 'one byte at a time should match toString');
-  assert.equal(res2, res3, 'all bytes at once should match toString');
-}
diff --git a/test/simple/test-string-decoder.js b/test/simple/test-string-decoder.js
deleted file mode 100644
index 7f69f7e..0000000
--- a/test/simple/test-string-decoder.js
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright Joyent, Inc. and other Node contributors.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to permit
-// persons to whom the Software is furnished to do so, subject to the
-// following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-// USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-var common = require('../common');
-var assert = require('assert');
-var StringDecoder = require('../../').StringDecoder;
-var decoder = new StringDecoder('utf8');
-
-
-
-var buffer = new Buffer('$');
-assert.deepEqual('$', decoder.write(buffer));
-
-buffer = new Buffer('¢');
-assert.deepEqual('', decoder.write(buffer.slice(0, 1)));
-assert.deepEqual('¢', decoder.write(buffer.slice(1, 2)));
-
-buffer = new Buffer('€');
-assert.deepEqual('', decoder.write(buffer.slice(0, 1)));
-assert.deepEqual('', decoder.write(buffer.slice(1, 2)));
-assert.deepEqual('€', decoder.write(buffer.slice(2, 3)));
-
-buffer = new Buffer([0xF0, 0xA4, 0xAD, 0xA2]);
-var s = '';
-s += decoder.write(buffer.slice(0, 1));
-s += decoder.write(buffer.slice(1, 2));
-s += decoder.write(buffer.slice(2, 3));
-s += decoder.write(buffer.slice(3, 4));
-assert.ok(s.length > 0);
-
-// CESU-8
-buffer = new Buffer('EDA0BDEDB18D', 'hex'); // THUMBS UP SIGN (in CESU-8)
-var s = '';
-s += decoder.write(buffer.slice(0, 1));
-s += decoder.write(buffer.slice(1, 2));
-s += decoder.write(buffer.slice(2, 3)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(3, 4));
-s += decoder.write(buffer.slice(4, 5));
-s += decoder.write(buffer.slice(5, 6)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 2));
-s += decoder.write(buffer.slice(2, 4)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(4, 6)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 3)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(3, 6)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 4)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(4, 5));
-s += decoder.write(buffer.slice(5, 6)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 5)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(5, 6)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 6));
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-
-// UCS-2
-decoder = new StringDecoder('ucs2');
-buffer = new Buffer('ab', 'ucs2');
-assert.equal(decoder.write(buffer), 'ab'); // 2 complete chars
-buffer = new Buffer('abc', 'ucs2');
-assert.equal(decoder.write(buffer.slice(0, 3)), 'a'); // 'a' and first of 'b'
-assert.equal(decoder.write(buffer.slice(3, 6)), 'bc'); // second of 'b' and 'c'
-
-
-// UTF-16LE
-buffer = new Buffer('3DD84DDC', 'hex'); // THUMBS UP SIGN (in CESU-8)
-var s = '';
-s += decoder.write(buffer.slice(0, 1));
-s += decoder.write(buffer.slice(1, 2)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(2, 3));
-s += decoder.write(buffer.slice(3, 4)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 2)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(2, 4)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 3)); // complete lead surrogate
-assert.equal(s, '');
-s += decoder.write(buffer.slice(3, 4)); // complete trail surrogate
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-var s = '';
-s += decoder.write(buffer.slice(0, 4));
-assert.equal(s, '\uD83D\uDC4D'); // THUMBS UP SIGN (in UTF-16)
-
-
-// A mixed ascii and non-ascii string
-// Test stolen from deps/v8/test/cctest/test-strings.cc
-// U+02E4 -> CB A4
-// U+0064 -> 64
-// U+12E4 -> E1 8B A4
-// U+0030 -> 30
-// U+3045 -> E3 81 85
-var expected = '\u02e4\u0064\u12e4\u0030\u3045';
-var buffer = new Buffer([0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4,
-                         0x30, 0xE3, 0x81, 0x85]);
-var charLengths = [0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5];
-
-// Split the buffer into 3 segments
-//  |----|------|-------|
-//  0    i      j       buffer.length
-// Scan through every possible 3 segment combination
-// and make sure that the string is always parsed.
-common.print('scanning ');
-for (var j = 2; j < buffer.length; j++) {
-  for (var i = 1; i < j; i++) {
-    var decoder = new StringDecoder('utf8');
-
-    var sum = decoder.write(buffer.slice(0, i));
-
-    // just check that we've received the right amount
-    // after the first write
-    assert.equal(charLengths[i], sum.length);
-
-    sum += decoder.write(buffer.slice(i, j));
-    sum += decoder.write(buffer.slice(j, buffer.length));
-    assert.equal(expected, sum);
-    common.print('.');
-  }
-}
-console.log(' crayon!');
-

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-string-decoder.git



More information about the Pkg-javascript-commits mailing list