diff --git a/.airtap.yml b/.airtap.yml new file mode 100644 index 0000000000..38e6f0349e --- /dev/null +++ b/.airtap.yml @@ -0,0 +1,17 @@ +sauce_connect: true +browsers: + - name: chrome + version: latest + platform: Windows 10 + - name: internet explorer + version: latest + platform: Windows 10 + - name: firefox + version: latest + platform: Windows 10 + - name: safari + version: latest + platform: Mac 10.13 + - name: microsoftedge + version: latest + platform: Windows 10 diff --git a/.gitignore b/.gitignore index f768783ace..27e4893f19 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules/ coverage package-lock.json *.tap +.airtaprc diff --git a/.travis.yml b/.travis.yml index 40992555bf..94374dc018 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,55 +1,22 @@ sudo: false language: node_js -before_install: - - npm install -g npm@2 - - test $NPM_LEGACY && npm install -g npm@latest-3 || npm install npm -g notifications: email: false matrix: fast_finish: true include: - - node_js: '0.8' - env: - - TASK=test - - NPM_LEGACY=true - - node_js: '0.10' - env: - - TASK=test - - NPM_LEGACY=true - - node_js: '0.11' - env: - - TASK=test - - NPM_LEGACY=true - - node_js: '0.12' - env: - - TASK=test - - NPM_LEGACY=true - - node_js: 1 - env: - - TASK=test - - NPM_LEGACY=true - - node_js: 2 - env: - - TASK=test - - NPM_LEGACY=true - - node_js: 3 - env: - - TASK=test - - NPM_LEGACY=true - - node_js: 4 - env: TASK=test - - node_js: 5 - env: TASK=test - node_js: 6 - env: TASK=test - - node_js: 7 - env: TASK=test + env: CMD=test - node_js: 8 - env: TASK=test + env: CMD=test - node_js: 9 - env: TASK=test -script: "npm run $TASK" -env: - global: - - secure: rE2Vvo7vnjabYNULNyLFxOyt98BoJexDqsiOnfiD6kLYYsiQGfr/sbZkPMOFm9qfQG7pjqx+zZWZjGSswhTt+626C0t/njXqug7Yps4c3dFblzGfreQHp7wNX5TFsvrxd6dAowVasMp61sJcRnB2w8cUzoe3RAYUDHyiHktwqMc= - - secure: g9YINaKAdMatsJ28G9jCGbSaguXCyxSTy+pBO6Ch0Cf57ZLOTka3HqDj8p3nV28LUIHZ3ut5WO43CeYKwt4AUtLpBS3a0dndHdY6D83uY6b2qh5hXlrcbeQTq2cvw2y95F7hm4D1kwrgZ7ViqaKggRcEupAL69YbJnxeUDKWEdI= + env: CMD=test + - node_js: 10 + env: CMD=test + - node_js: stable + env: CMD=test-browsers + addons: + sauce_connect: true + hosts: + - airtap.local +script: npm run $CMD diff --git a/README.md b/README.md index 174ff9d294..1c9c6afe12 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,86 @@ # readable-stream -***Node-core v8.11.1 streams for userland*** [![Build Status](https://travis-ci.org/nodejs/readable-stream.svg?branch=master)](https://travis-ci.org/nodejs/readable-stream) +***Node.js core streams for userland*** [![Build Status](https://travis-ci.com/nodejs/readable-stream.svg?branch=master)](https://travis-ci.com/nodejs/readable-stream) [![NPM](https://nodei.co/npm/readable-stream.png?downloads=true&downloadRank=true)](https://nodei.co/npm/readable-stream/) [![NPM](https://nodei.co/npm-dl/readable-stream.png?&months=6&height=3)](https://nodei.co/npm/readable-stream/) -[![Sauce Test Status](https://saucelabs.com/browser-matrix/readable-stream.svg)](https://saucelabs.com/u/readable-stream) +[![Sauce Test Status](https://saucelabs.com/browser-matrix/readabe-stream.svg)](https://saucelabs.com/u/readabe-stream) ```bash npm install --save readable-stream ``` -***Node-core streams for userland*** +This package is a mirror of the streams implementations in Node.js. -This package is a mirror of the Streams2 and Streams3 implementations in -Node-core. - -Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v8.11.1/docs/api/stream.html). +Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v10.8.0/docs/api/stream.html). If you want to guarantee a stable streams base, regardless of what version of Node you, or the users of your libraries are using, use **readable-stream** *only* and avoid the *"stream"* module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html). As of version 2.0.0 **readable-stream** uses semantic versioning. +## Version 3.x.x + +v3.x.x of `readable-stream` supports Node 6, 8, and 10, as well as +evergreen browsers, IE 11 and latest Safari. The breaking changes +introduced by v3 are composed by the combined breaking changes in [Node v9](https://nodejs.org/en/blog/release/v9.0.0/) +and [Node v10](https://nodejs.org/en/blog/release/v10.0.0/), as follows: + +1. Error codes: https://github.com/nodejs/node/pull/13310, + https://github.com/nodejs/node/pull/13291, + https://github.com/nodejs/node/pull/16589, + https://github.com/nodejs/node/pull/15042, + https://github.com/nodejs/node/pull/15665, + https://github.com/nodejs/readable-stream/pull/344 +2. 'readable' have precedence over flowing + https://github.com/nodejs/node/pull/18994 +3. make virtual methods errors consistent + https://github.com/nodejs/node/pull/18813 +4. updated streams error handling + https://github.com/nodejs/node/pull/18438 +5. writable.end should return this. + https://github.com/nodejs/node/pull/18780 +6. readable continues to read when push('') + https://github.com/nodejs/node/pull/18211 +7. add custom inspect to BufferList + https://github.com/nodejs/node/pull/17907 +8. always defer 'readable' with nextTick + https://github.com/nodejs/node/pull/17979 + +## Version 2.x.x + +v2.x.x of `readable-stream` supports all Node.js version from 0.8, as well as +evergreen browsers and IE 10 & 11. + +### Big Thanks + +Cross-browser Testing Platform and Open Source <3 Provided by [Sauce Labs][sauce] + +# Usage + +You can swap your `require('stream')` with `require('readable-stream')` +without any changes, if you are just using one of the main classes and +functions. + +```js +const { + Readable, + Writable, + Transform, + Duplex, + pipeline, + finished +} = require('readable-stream') +```` + +Note that `require('stream')` will return `Stream`, while +`require('readable-stream')` will return `Readable`. We discourage using +whatever is exported directly, but rather use one of the properties as +shown in the example above. + # Streams Working Group `readable-stream` is maintained by the Streams Working Group, which @@ -51,3 +107,5 @@ Node.js. The responsibilities of the Streams Working Group include: - Release GPG key: 3ABC01543F22DD2239285CDD818674489FBC127E * **Irina Shestak** ([@lrlna](https://github.com/lrlna)) <shestak.irina@gmail.com> * **Yoshua Wyuts** ([@yoshuawuyts](https://github.com/yoshuawuyts)) <yoshuawuyts@gmail.com> + +[sauce]: https://saucelabs.com diff --git a/build/build.js b/build/build.js index 2580303c87..ee363ab3ee 100644 --- a/build/build.js +++ b/build/build.js @@ -36,7 +36,7 @@ if (!usageVersionRegex.test(nodeVersion)) { } // `inputLoc`: URL or local path. -function processFile (inputLoc, out, replacements) { +function processFile (inputLoc, out, replacements, addAtEnd) { var file = fs.createReadStream(inputLoc, encoding) file.pipe(bl(function (err, data) { @@ -55,6 +55,10 @@ function processFile (inputLoc, out, replacements) { } data = data.replace(regexp, arg2) }) + + if (addAtEnd) { + data += addAtEnd + } if (inputLoc.slice(-3) === '.js') { try { const transformed = babel.transform(data, { @@ -68,7 +72,11 @@ function processFile (inputLoc, out, replacements) { ['transform-es2015-classes', { loose: true }], 'transform-es2015-destructuring', 'transform-es2015-computed-properties', - 'transform-es2015-spread' + 'transform-es2015-spread', + 'transform-optional-catch-binding', + 'transform-inline-imports-commonjs', + 'transform-async-to-generator', + 'transform-async-generator-functions' ] }) data = transformed.code @@ -113,7 +121,7 @@ function processTestFile (file) { if (testReplace[file]) replacements = replacements.concat(testReplace[file]) - processFile(url, out, replacements) + processFile(url, out, replacements, ';require(\'tap\').pass(\'sync run\');var _list = process.listeners(\'uncaughtException\'); process.removeAllListeners(\'uncaughtException\'); _list.pop(); _list.forEach((e) => process.on(\'uncaughtException\', e));') } //-------------------------------------------------------------------- diff --git a/build/files.js b/build/files.js index 9bf53a6ee4..8fbc8cf20d 100644 --- a/build/files.js +++ b/build/files.js @@ -41,8 +41,12 @@ const headRegexp = /(^module.exports = \w+;?)/m , utilReplacement = [ /^const util = require\('util'\);/m - , '\n/**/\nconst util = require(\'core-util-is\');\n' - + 'util.inherits = require(\'inherits\');\n/**/\n' + , '' + ] + + , inherits = [ + /^util.inherits/m + , 'require(\'inherits\')' ] , debugLogReplacement = [ @@ -72,16 +76,6 @@ const headRegexp = /(^module.exports = \w+;?)/m + '}catch(_){}}());\n' ] - , isArrayDefine = [ - headRegexp - , '$1\n\n/**/\nvar isArray = require(\'isarray\');\n/**/\n' - ] - - , isArrayReplacement = [ - /Array\.isArray/g - , 'isArray' - ] - , objectKeysDefine = require('./common-replacements').objectKeysDefine , objectKeysReplacement = require('./common-replacements').objectKeysReplacement @@ -156,13 +150,6 @@ const headRegexp = /(^module.exports = \w+;?)/m } ` ] - , safeBufferFix = [ - /(?:var|const) (?:{ )Buffer(?: }) = require\('buffer'\)(?:\.Buffer)?;/, - `/**/ - var Buffer = require('safe-buffer').Buffer; -/**/ -` - ] , internalDirectory = [ /require\('internal\/streams\/([a-zA-z]+)'\)/g, 'require(\'./internal/streams/$1\')' @@ -176,9 +163,9 @@ const headRegexp = /(^module.exports = \w+;?)/m , `function(er) { onwrite(stream, er); }` ] , addUintStuff = [ - /(?:var|const) Buffer = require\('safe-buffer'\)\.Buffer;/ + /(?:var|const) (?:{ )Buffer(?: }) = require\('buffer'\)(?:\.Buffer)?;/g , ` - const Buffer = require('safe-buffer').Buffer + const Buffer = require('buffer').Buffer const OurUint8Array = global.Uint8Array || function () {} function _uint8ArrayToBuffer(chunk) { return Buffer.from(chunk); @@ -230,23 +217,39 @@ function CorkedRequest(state) { /Buffer\.prototype\.copy\.call\(src, target, offset\);/ , 'src.copy(target, offset);' ] + , errorsOneLevel = [ + /internal\/errors/ + , '../errors' + ] + , errorsTwoLevel = [ + /internal\/errors/ + , '../../../errors' + ] + , warnings = [ + /^const { emitExperimentalWarning } = require\('internal\/util'\);/m, + 'const { emitExperimentalWarning } = require(\'../experimentalWarning\');' + ] module.exports['_stream_duplex.js'] = [ requireReplacement , instanceofReplacement , utilReplacement + , inherits , stringDecoderReplacement , objectKeysReplacement , objectKeysDefine , processNextTickImport , processNextTickReplacement + , errorsOneLevel ] module.exports['_stream_passthrough.js'] = [ requireReplacement , instanceofReplacement , utilReplacement + , inherits , stringDecoderReplacement + , errorsOneLevel ] module.exports['_stream_readable.js'] = [ @@ -257,10 +260,9 @@ module.exports['_stream_readable.js'] = [ , altIndexOfImplReplacement , altIndexOfUseReplacement , stringDecoderReplacement - , isArrayReplacement - , isArrayDefine , debugLogReplacement , utilReplacement + , inherits , stringDecoderReplacement , eventEmittterReplacement , requireStreamReplacement @@ -269,16 +271,19 @@ module.exports['_stream_readable.js'] = [ , processNextTickReplacement , eventEmittterListenerCountReplacement , internalDirectory - , safeBufferFix , fixUintStuff , addUintStuff + , errorsOneLevel + , warnings ] module.exports['_stream_transform.js'] = [ requireReplacement , instanceofReplacement , utilReplacement + , inherits , stringDecoderReplacement + , errorsOneLevel ] module.exports['_stream_writable.js'] = [ @@ -287,6 +292,7 @@ module.exports['_stream_writable.js'] = [ , requireReplacement , instanceofReplacement , utilReplacement + , inherits , stringDecoderReplacement , debugLogReplacement , deprecateReplacement @@ -304,20 +310,20 @@ module.exports['_stream_writable.js'] = [ , fixInstanceCheck , removeOnWriteBind , internalDirectory - , safeBufferFix , fixUintStuff , addUintStuff , fixBufferCheck , useWriteReq , useCorkedRequest , addConstructors + , errorsOneLevel ] -module.exports['internal/streams/BufferList.js'] = [ +module.exports['internal/streams/buffer_list.js'] = [ [ /(?:var|const) (?:{ )Buffer(?: }) = require\('buffer'\)(?:\.Buffer)?;/, ` -const Buffer = require('safe-buffer').Buffer +const Buffer = require('buffer').Buffer const util = require('util') ` ] @@ -339,4 +345,33 @@ if (util && util.inspect && util.inspect.custom) { module.exports['internal/streams/destroy.js'] = [ processNextTickImport , processNextTickReplacement + , errorsTwoLevel +] + +module.exports['internal/streams/state.js'] = [ + processNextTickImport + , processNextTickReplacement + , errorsTwoLevel +] + +module.exports['internal/streams/async_iterator.js'] = [ + processNextTickImport + , processNextTickReplacement + , errorsTwoLevel +] + +module.exports['internal/streams/end-of-stream.js'] = [ + processNextTickImport + , processNextTickReplacement + , errorsTwoLevel +] + +module.exports['internal/streams/pipeline.js'] = [ + processNextTickImport + , processNextTickReplacement + , errorsTwoLevel + , [ + /require\('internal\/streams\/end-of-stream'\)/, + 'require(\'.\/end-of-stream\')' + ] ] diff --git a/build/package.json b/build/package.json deleted file mode 100644 index cf2a76902f..0000000000 --- a/build/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "readable-stream-build", - "version": "0.0.0", - "description": "", - "main": "build.js", - "dependencies": { - "babel-core": "^6.26.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.5.2", - "babel-plugin-transform-es2015-block-scoping": "^6.26.0", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-destructuring": "^6.18.0", - "babel-plugin-transform-es2015-for-of": "^6.8.0", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.8.0", - "bl": "^1.2.1", - "glob": "^7.1.2", - "gunzip-maybe": "^1.4.1", - "hyperquest": "^2.1.3", - "pump": "^3.0.0", - "rimraf": "^2.6.2", - "tar-fs": "^1.16.0" - } -} diff --git a/build/test-replacements.js b/build/test-replacements.js index 61ee998586..265318438e 100644 --- a/build/test-replacements.js +++ b/build/test-replacements.js @@ -12,6 +12,23 @@ const altForEachImplReplacement = require('./common-replacements').altForEachImp require('./common-replacements').bufferStaticMethods , specialForEachReplacment = require('./common-replacements').specialForEachReplacment + , deepStrictEqual = [ + /util\.isDeepStrictEqual/, + 'require(\'deep-strict-equal\')' + ] + , tapOk = [ + /console\.log\('ok'\);/g, + 'require(\'tap\').pass();' + ] + , catchES7 = [ + /} catch {/, + '} catch(_e) {' + ] + , catchES7OpenClose = [ + /} catch {}/, + '} catch(_e) {}' + ] + module.exports.all = [ [ @@ -73,32 +90,21 @@ module.exports['test-stream-big-packet.js'] = [ , altIndexOfUseReplacement ] +module.exports['test-stream-end-paused.js'] = [ + [ + /console.log\('ok'\);/, + '' + ] +] + module.exports['common.js'] = [ objectKeysDefine , objectKeysReplacement , altForEachImplReplacement , altForEachUseReplacement - - , [ - /(exports.mustCall[\s\S]*)/m - , '$1\n' - + 'if (!util._errnoException) {\n' - + ' var uv;\n' - + ' util._errnoException = function(err, syscall) {\n' - + ' if (util.isUndefined(uv)) try { uv = process.binding(\'uv\'); } catch (e) {}\n' - + ' var errname = uv ? uv.errname(err) : \'\';\n' - + ' var e = new Error(syscall + \' \' + errname);\n' - + ' e.code = errname;\n' - + ' e.errno = errname;\n' - + ' e.syscall = syscall;\n' - + ' return e;\n' - + ' };\n' - + '}\n' - ] - - // for streams2 on node 0.11 - // and dtrace in 0.10 - // and coverage in all + , deepStrictEqual + , catchES7 + , catchES7OpenClose , [ /^( for \(var x in global\) \{|function leakedGlobals\(\) \{)$/m , ' /**/\n' @@ -110,27 +116,27 @@ module.exports['common.js'] = [ + ' 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])})' + + '\'console,clearImmediate,setImmediate,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])})' + ' /**/\n\n$1' ] - // for node 0.8 , [ - /^/ - , '/**/' - + '\nif (!global.setImmediate) {\n' - + ' global.setImmediate = function setImmediate(fn) {\n' - - + ' return setTimeout(fn.bind.apply(fn, arguments), 4);\n' - + ' };\n' - + '}\n' - + 'if (!global.clearImmediate) {\n' - + ' global.clearImmediate = function clearImmediate(i) {\n' - + ' return clearTimeout(i);\n' + /(exports.mustCall[\s\S]*)/m + , '$1\n' + + 'if (!util._errnoException) {\n' + + ' var uv;\n' + + ' util._errnoException = function(err, syscall) {\n' + + ' if (util.isUndefined(uv)) try { uv = process.binding(\'uv\'); } catch (e) {}\n' + + ' var errname = uv ? uv.errname(err) : \'\';\n' + + ' var e = new Error(syscall + \' \' + errname);\n' + + ' e.code = errname;\n' + + ' e.errno = errname;\n' + + ' e.syscall = syscall;\n' + + ' return e;\n' + ' };\n' + '}\n' - + '/**/\n' ] + , [ /^if \(global\.ArrayBuffer\) \{([^\}]+)\}$/m , '/**/if (!process.browser) {' @@ -193,6 +199,10 @@ module.exports['common.js'] = [ /\}\).enable\(\);/, '}).enable();*/' ], +[ + /const async_hooks = require\('async_hooks'\)/, + 'var async_hooks = require(\'async_\' + \'hooks\')' +], [ /(?:var|const) async_wrap = process\.binding\('async_wrap'\);\n.*(?:var|const) (?:{ )?kCheck(?: })? = async_wrap\.constants(?:\.kCheck)?;/gm, '// const async_wrap = process.binding(\'async_wrap\');\n' + @@ -301,17 +311,56 @@ module.exports['test-stream3-cork-uncork.js'] = module.exports['test-stream3-cor ] module.exports['test-stream2-readable-from-list.js'] = [ [ - /require\('internal\/streams\/BufferList'\)/, - 'require(\'../../lib/internal/streams/BufferList\')' + /require\('internal\/streams\/buffer_list'\)/, + 'require(\'../../lib/internal/streams/buffer_list\')' ] ] module.exports['test-stream-writev.js'] = [ + tapOk, [ - /'latin1'/g, - `'binary'` + /console.log\(`# decode=/, + 'require(\'tap\').test(`# decode=' ] ] + +module.exports['test-stream3-pause-then-read.js'] = [ + tapOk +] + +module.exports['test-stream-unshift-read-race.js'] = [ + tapOk +] + +module.exports['test-stream2-unpipe-leak.js'] = [ + tapOk +] + +module.exports['test-stream2-compatibility.js'] = [ + tapOk +] + +module.exports['test-stream-push-strings.js'] = [ + tapOk +] + +module.exports['test-stream-unshift-empty-chunk.js'] = [ + tapOk +] + +module.exports['test-stream2-pipe-error-once-listener.js'] = [ + tapOk +] + +module.exports['test-stream-push-order.js'] = [ + tapOk +] + +module.exports['test-stream2-push.js'] = [ + tapOk +] + module.exports['test-stream2-readable-empty-buffer-no-eof.js'] = [ + tapOk, [ /case 3:\n(\s+)setImmediate\(r\.read\.bind\(r, 0\)\);/, 'case 3:\n$1setTimeout(r.read.bind(r, 0), 50);' @@ -319,8 +368,8 @@ module.exports['test-stream2-readable-empty-buffer-no-eof.js'] = [ ] module.exports['test-stream-buffer-list.js'] = [ [ - /require\('internal\/streams\/BufferList'\);/, - 'require(\'../../lib/internal/streams/BufferList\');' + /require\('internal\/streams\/buffer_list'\);/, + 'require(\'../../lib/internal/streams/buffer_list\');' ] ] @@ -337,3 +386,53 @@ module.exports['test-stream-unpipe-event.js'] = [ 'if (process.version.indexOf(\'v0.8\') === 0) { process.exit(0) }\n' ] ] + +module.exports['test-stream-readable-flow-recursion.js'] = [ + tapOk, + deepStrictEqual +] + +module.exports['test-stream-readable-with-unimplemented-_read.js'] = [ + deepStrictEqual +] + +module.exports['test-stream-writable-needdrain-state.js'] = [ + deepStrictEqual +] + +module.exports['test-stream-readable-setEncoding-null.js'] = [ + deepStrictEqual +] + +module.exports['test-stream-pipeline.js'] = [ + [ + /require\('http2'\)/g, + '{ createServer() { return { listen() {} } } }' + ], + [ + /assert\.deepStrictEqual\(err, new Error\('kaboom'\)\);/g, + 'assert.strictEqual(err.message, \'kaboom\');' + ], + [ + /cb\(new Error\('kaboom'\)\)/g, + 'process.nextTick(cb, new Error(\'kaboom\'))' + ], + [ + /const \{ promisify \} = require\('util'\);/g, + 'const promisify = require(\'util-promisify\');' + ] +] + +module.exports['test-stream-finished.js'] = [ + [ + /const \{ promisify \} = require\('util'\);/g, + 'const promisify = require(\'util-promisify\');' + ] +] + +module.exports['test-stream-readable-async-iterators.js'] = [ + [ + /assert.rejects\(/g, + '(function(f, e) { let success = false; f().then(function() { success = true; throw new Error(\'should not succeeed\') }).catch(function(e2) { if (success) { throw e2; } assert.strictEqual(e.message, e2.message); })})(' + ] +] diff --git a/duplex-browser.js b/duplex-browser.js deleted file mode 100644 index f8b2db83db..0000000000 --- a/duplex-browser.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/_stream_duplex.js'); diff --git a/duplex.js b/duplex.js deleted file mode 100644 index 46924cbfdf..0000000000 --- a/duplex.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./readable').Duplex diff --git a/errors-browser.js b/errors-browser.js new file mode 100644 index 0000000000..26c5d2635e --- /dev/null +++ b/errors-browser.js @@ -0,0 +1,61 @@ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var codes = {}; + +function createErrorType(code, message, Base) { + if (!Base) { + Base = Error; + } + + function getMessage(arg1, arg2) { + if (typeof message === 'string') { + return message; + } else { + return message(arg1, arg2); + } + } + + var NodeError = function (_Base) { + _inherits(NodeError, _Base); + + function NodeError(arg1, arg2) { + _classCallCheck(this, NodeError); + + return _possibleConstructorReturn(this, (NodeError.__proto__ || Object.getPrototypeOf(NodeError)).call(this, getMessage(arg1, arg2))); + } + + return NodeError; + }(Base); + + NodeError.prototype.name = Base.name; + NodeError.prototype.code = code; + + codes[code] = NodeError; +} + +createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) { + return 'The value "' + value + '" is invalid for option "' + name + '"'; +}, TypeError); +createErrorType('ERR_INVALID_ARG_TYPE', 'argument must be of the right type', TypeError); +createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); +createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) { + return 'The ' + name + ' method is not implemented'; +}); +createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'premature close'); +createErrorType('ERR_STREAM_DESTROYED', 'the stream was destroyed'); +createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); +createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); +createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end'); +createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError); +createErrorType('ERR_UNKNOWN_ENCODING', function (arg) { + return 'Unknown encoding: ' + arg; +}, TypeError); +createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event'); + +module.exports.codes = codes; diff --git a/errors.js b/errors.js new file mode 100644 index 0000000000..428398360b --- /dev/null +++ b/errors.js @@ -0,0 +1,49 @@ +'use strict'; + +const codes = {}; + +function createErrorType(code, message, Base) { + if (!Base) { + Base = Error + } + + function getMessage (arg1, arg2) { + if (typeof message === 'string') { + return message + } else { + return message(arg1, arg2) + } + } + + class NodeError extends Base { + constructor (arg1, arg2) { + super(getMessage(arg1, arg2)); + } + } + + NodeError.prototype.name = Base.name; + NodeError.prototype.code = code; + + codes[code] = NodeError; +} + +createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) { + return 'The value "' + value + '" is invalid for option "' + name + '"' +}, TypeError); +createErrorType('ERR_INVALID_ARG_TYPE', 'argument must be of the right type', TypeError); +createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); +createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) { + return 'The ' + name + ' method is not implemented' +}); +createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'premature close'); +createErrorType('ERR_STREAM_DESTROYED', 'the stream was destroyed'); +createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); +createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); +createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end'); +createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError); +createErrorType('ERR_UNKNOWN_ENCODING', function (arg) { + return 'Unknown encoding: ' + arg +}, TypeError); +createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event'); + +module.exports.codes = codes; diff --git a/experimentalWarning.js b/experimentalWarning.js new file mode 100644 index 0000000000..27003face2 --- /dev/null +++ b/experimentalWarning.js @@ -0,0 +1,13 @@ +'use strict' + +var experimentalWarnings = new Set(); + +function emitExperimentalWarning(feature) { + if (experimentalWarnings.has(feature)) return; + var msg = feature + ' is an experimental feature. This feature could ' + + 'change at any time'; + experimentalWarnings.add(feature); + process.emitWarning(msg, 'ExperimentalWarning'); +} + +module.exports.emitExperimentalWarning = emitExperimentalWarning; diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js index a1ca813e5a..e8839b1419 100644 --- a/lib/_stream_duplex.js +++ b/lib/_stream_duplex.js @@ -42,18 +42,13 @@ var objectKeys = Object.keys || function (obj) { module.exports = Duplex; -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - var Readable = require('./_stream_readable'); var Writable = require('./_stream_writable'); -util.inherits(Duplex, Readable); +require('inherits')(Duplex, Readable); { - // avoid scope creep, the keys array can then be collected + // Allow the keys array to be GC'ed. var keys = objectKeys(Writable.prototype); for (var v = 0; v < keys.length; v++) { var method = keys[v]; @@ -66,15 +61,18 @@ function Duplex(options) { Readable.call(this, options); Writable.call(this, options); + this.allowHalfOpen = true; - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; + if (options) { + if (options.readable === false) this.readable = false; - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; + if (options.writable === false) this.writable = false; - this.once('end', onend); + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } + } } Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { @@ -87,11 +85,30 @@ Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { } }); +Object.defineProperty(Duplex.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState && this._writableState.getBuffer(); + } +}); + +Object.defineProperty(Duplex.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.length; + } +}); + // the no-half-open enforcer function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; + // If the writable side ended, then we're ok. + if (this._writableState.ended) return; // no more data can be written. // But allow more writes to happen in this tick. @@ -103,6 +120,10 @@ function onEndNT(self) { } Object.defineProperty(Duplex.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, get: function () { if (this._readableState === undefined || this._writableState === undefined) { return false; @@ -121,11 +142,4 @@ Object.defineProperty(Duplex.prototype, 'destroyed', { this._readableState.destroyed = value; this._writableState.destroyed = value; } -}); - -Duplex.prototype._destroy = function (err, cb) { - this.push(null); - this.end(); - - pna.nextTick(cb, err); -}; \ No newline at end of file +}); \ No newline at end of file diff --git a/lib/_stream_passthrough.js b/lib/_stream_passthrough.js index a9c8358848..a3ab801b5b 100644 --- a/lib/_stream_passthrough.js +++ b/lib/_stream_passthrough.js @@ -29,12 +29,7 @@ module.exports = PassThrough; var Transform = require('./_stream_transform'); -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - -util.inherits(PassThrough, Transform); +require('inherits')(PassThrough, Transform); function PassThrough(options) { if (!(this instanceof PassThrough)) return new PassThrough(options); diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index bf34ac65e1..fec906e7d5 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -28,10 +28,6 @@ var pna = require('process-nextick-args'); module.exports = Readable; -/**/ -var isArray = require('isarray'); -/**/ - /**/ var Duplex; /**/ @@ -50,9 +46,7 @@ var EElistenerCount = function (emitter, type) { var Stream = require('./internal/streams/stream'); /**/ -/**/ - -var Buffer = require('safe-buffer').Buffer; +var Buffer = require('buffer').Buffer; var OurUint8Array = global.Uint8Array || function () {}; function _uint8ArrayToBuffer(chunk) { return Buffer.from(chunk); @@ -61,13 +55,6 @@ function _isUint8Array(obj) { return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; } -/**/ - -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - /**/ var debugUtil = require('util'); var debug = void 0; @@ -78,11 +65,28 @@ if (debugUtil && debugUtil.debuglog) { } /**/ -var BufferList = require('./internal/streams/BufferList'); +var BufferList = require('./internal/streams/buffer_list'); var destroyImpl = require('./internal/streams/destroy'); -var StringDecoder; -util.inherits(Readable, Stream); +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; + +var _require2 = require('../experimentalWarning'), + emitExperimentalWarning = _require2.emitExperimentalWarning; + +// Lazy loaded to improve the startup performance. + + +var StringDecoder = void 0; +var ReadableAsyncIterator = void 0; + +require('inherits')(Readable, Stream); var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; @@ -95,10 +99,10 @@ function prependListener(emitter, event, fn) { // userland ones. NEVER DO THIS. This is here only because this code needs // to continue to work with older versions of Node.js that do not include // the prependListener() method. The goal is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; } -function ReadableState(options, stream) { +function ReadableState(options, stream, isDuplex) { Duplex = Duplex || require('./_stream_duplex'); options = options || {}; @@ -108,7 +112,7 @@ function ReadableState(options, stream) { // However, some cases require setting options to different // values for the readable and the writable sides of the duplex stream. // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to // make all the buffer merging and length checks go away @@ -118,14 +122,7 @@ function ReadableState(options, stream) { // the point at which it stops calling _read() to fill the buffer // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var readableHwm = options.readableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); + this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the // linked list can remove elements from the beginning faster than @@ -152,6 +149,9 @@ function ReadableState(options, stream) { this.readableListening = false; this.resumeScheduled = false; + // Should close be emitted on destroy. Defaults to true. + this.emitClose = options.emitClose !== false; + // has it been destroyed this.destroyed = false; @@ -180,7 +180,11 @@ function Readable(options) { if (!(this instanceof Readable)) return new Readable(options); - this._readableState = new ReadableState(options, this); + // Checking for a Stream.Duplex instance is faster here instead of inside + // the ReadableState constructor, at least with V8 6.5 + var isDuplex = this instanceof Duplex; + + this._readableState = new ReadableState(options, this, isDuplex); // legacy this.readable = true; @@ -195,6 +199,10 @@ function Readable(options) { } Object.defineProperty(Readable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, get: function () { if (this._readableState === undefined) { return false; @@ -217,7 +225,6 @@ Object.defineProperty(Readable.prototype, 'destroyed', { Readable.prototype.destroy = destroyImpl.destroy; Readable.prototype._undestroy = destroyImpl.undestroy; Readable.prototype._destroy = function (err, cb) { - this.push(null); cb(err); }; @@ -251,6 +258,7 @@ Readable.prototype.unshift = function (chunk) { }; function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + debug('readableAddChunk', chunk); var state = stream._readableState; if (chunk === null) { state.reading = false; @@ -266,9 +274,11 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { } if (addToFront) { - if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); + if (state.endEmitted) stream.emit('error', new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true); } else if (state.ended) { - stream.emit('error', new Error('stream.push() after EOF')); + stream.emit('error', new ERR_STREAM_PUSH_AFTER_EOF()); + } else if (state.destroyed) { + return false; } else { state.reading = false; if (state.decoder && !encoding) { @@ -280,16 +290,20 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { } } else if (!addToFront) { state.reading = false; + maybeReadMore(stream, state); } } - return needMoreData(state); + // We can push more data if we are below the highWaterMark. + // Also, if we have no data yet, we can stand some more bytes. + // This is to work around cases where hwm=0, such as the repl. + return !state.ended && (state.length < state.highWaterMark || state.length === 0); } function addChunk(stream, state, chunk, addToFront) { if (state.flowing && state.length === 0 && !state.sync) { + state.awaitDrain = 0; stream.emit('data', chunk); - stream.read(0); } else { // update the buffer info. state.length += state.objectMode ? 1 : chunk.length; @@ -303,22 +317,11 @@ function addChunk(stream, state, chunk, addToFront) { function chunkInvalid(state, chunk) { var er; if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); } return er; } -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - Readable.prototype.isPaused = function () { return this._readableState.flowing === false; }; @@ -327,7 +330,8 @@ Readable.prototype.isPaused = function () { Readable.prototype.setEncoding = function (enc) { if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; + // if setEncoding(null), decoder.encoding equals utf8 + this._readableState.encoding = this._readableState.decoder.encoding; return this; }; @@ -355,7 +359,7 @@ function computeNewHighWaterMark(n) { function howMuchToRead(n, state) { if (n <= 0 || state.length === 0 && state.ended) return 0; if (state.objectMode) return 1; - if (n !== n) { + if (Number.isNaN(n)) { // Only flow one buffer at a time if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; } @@ -455,6 +459,7 @@ Readable.prototype.read = function (n) { n = 0; } else { state.length -= n; + state.awaitDrain = 0; } if (state.length === 0) { @@ -482,8 +487,19 @@ function onEofChunk(stream, state) { } state.ended = true; - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); + if (state.sync) { + // if we are sync, wait until next tick to emit the data. + // Otherwise we risk emitting data in the flow() + // the readable code triggers during a read() call + emitReadable(stream); + } else { + // emit 'readable' now to make sure it gets picked up. + state.needReadable = false; + if (!state.emittedReadable) { + state.emittedReadable = true; + emitReadable_(stream); + } + } } // Don't emit readable right away in sync mode, because this can trigger @@ -495,13 +511,24 @@ function emitReadable(stream) { if (!state.emittedReadable) { debug('emitReadable', state.flowing); state.emittedReadable = true; - if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream); + pna.nextTick(emitReadable_, stream); } } function emitReadable_(stream) { + var state = stream._readableState; debug('emit readable'); - stream.emit('readable'); + if (!state.destroyed && (state.length || state.ended)) { + stream.emit('readable'); + } + + // The stream needs another readable event if + // 1. It is not flowing, as the flow mechanism will take + // care of it. + // 2. It is not ended. + // 3. It is below the highWaterMark, so we can schedule + // another readable later. + state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark; flow(stream); } @@ -520,7 +547,7 @@ function maybeReadMore(stream, state) { function maybeReadMore_(stream, state) { var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { + while (!state.reading && !state.ended && state.length < state.highWaterMark) { debug('maybeReadMore read 0'); stream.read(0); if (len === state.length) @@ -535,7 +562,7 @@ function maybeReadMore_(stream, state) { // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function (n) { - this.emit('error', new Error('_read() is not implemented')); + this.emit('error', new ERR_METHOD_NOT_IMPLEMENTED('_read()')); }; Readable.prototype.pipe = function (dest, pipeOpts) { @@ -607,25 +634,19 @@ Readable.prototype.pipe = function (dest, pipeOpts) { if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); } - // If the user pushes more data while we're writing to dest then we'll end up - // in ondata again. However, we only want to increase awaitDrain once because - // dest will only emit one 'drain' event for the multiple writes. - // => Introduce a guard on increasing awaitDrain. - var increasedAwaitDrain = false; src.on('data', ondata); function ondata(chunk) { debug('ondata'); - increasedAwaitDrain = false; var ret = dest.write(chunk); - if (false === ret && !increasedAwaitDrain) { + debug('dest.write', ret); + if (ret === false) { // If the user unpiped during `dest.write()`, it is possible // to get stuck in a permanently paused state if that write // also returned false. // => Check whether `dest` is still a piping destination. if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - increasedAwaitDrain = true; + debug('false write response, pause', state.awaitDrain); + state.awaitDrain++; } src.pause(); } @@ -674,7 +695,7 @@ Readable.prototype.pipe = function (dest, pipeOpts) { }; function pipeOnDrain(src) { - return function () { + return function pipeOnDrainFunctionResult() { var state = src._readableState; debug('pipeOnDrain', state.awaitDrain); if (state.awaitDrain) state.awaitDrain--; @@ -718,7 +739,7 @@ Readable.prototype.unpipe = function (dest) { state.flowing = false; for (var i = 0; i < len; i++) { - dests[i].emit('unpipe', this, unpipeInfo); + dests[i].emit('unpipe', this, { hasUnpiped: false }); }return this; } @@ -739,19 +760,23 @@ Readable.prototype.unpipe = function (dest) { // Ensure readable listeners eventually get something Readable.prototype.on = function (ev, fn) { var res = Stream.prototype.on.call(this, ev, fn); + var state = this._readableState; if (ev === 'data') { - // Start flowing on next tick if stream isn't explicitly paused - if (this._readableState.flowing !== false) this.resume(); + // update readableListening so that resume() may be a no-op + // a few lines down. This is needed to support once('readable'). + state.readableListening = this.listenerCount('readable') > 0; + + // Try start flowing on next tick if stream isn't explicitly paused + if (state.flowing !== false) this.resume(); } else if (ev === 'readable') { - var state = this._readableState; if (!state.endEmitted && !state.readableListening) { state.readableListening = state.needReadable = true; state.emittedReadable = false; - if (!state.reading) { - pna.nextTick(nReadingNextTick, this); - } else if (state.length) { + if (state.length) { emitReadable(this); + } else if (!state.reading) { + pna.nextTick(nReadingNextTick, this); } } } @@ -760,6 +785,42 @@ Readable.prototype.on = function (ev, fn) { }; Readable.prototype.addListener = Readable.prototype.on; +Readable.prototype.removeListener = function (ev, fn) { + var res = Stream.prototype.removeListener.call(this, ev, fn); + + if (ev === 'readable') { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + pna.nextTick(updateReadableListening, this); + } + + return res; +}; + +Readable.prototype.removeAllListeners = function (ev) { + var res = Stream.prototype.removeAllListeners.apply(this, arguments); + + if (ev === 'readable' || ev === undefined) { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + pna.nextTick(updateReadableListening, this); + } + + return res; +}; + +function updateReadableListening(self) { + self._readableState.readableListening = self.listenerCount('readable') > 0; +} + function nReadingNextTick(self) { debug('readable nexttick read 0'); self.read(0); @@ -771,7 +832,9 @@ Readable.prototype.resume = function () { var state = this._readableState; if (!state.flowing) { debug('resume'); - state.flowing = true; + // we flow only if there is no one listening + // for readable + state.flowing = !state.readableListening; resume(this, state); } return this; @@ -785,13 +848,12 @@ function resume(stream, state) { } function resume_(stream, state) { + debug('resume', state.reading); if (!state.reading) { - debug('resume read 0'); stream.read(0); } state.resumeScheduled = false; - state.awaitDrain = 0; stream.emit('resume'); flow(stream); if (state.flowing && !state.reading) stream.read(0); @@ -799,7 +861,7 @@ function resume_(stream, state) { Readable.prototype.pause = function () { debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { + if (this._readableState.flowing !== false) { debug('pause'); this._readableState.flowing = false; this.emit('pause'); @@ -850,8 +912,8 @@ Readable.prototype.wrap = function (stream) { // important when wrapping filters and duplexes. for (var i in stream) { if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { + this[i] = function methodWrap(method) { + return function methodWrapReturnFunction() { return stream[method].apply(stream, arguments); }; }(i); @@ -876,6 +938,12 @@ Readable.prototype.wrap = function (stream) { return this; }; +Readable.prototype[Symbol.asyncIterator] = function () { + emitExperimentalWarning('Readable[Symbol.asyncIterator]'); + if (ReadableAsyncIterator === undefined) ReadableAsyncIterator = require('./internal/streams/async_iterator'); + return new ReadableAsyncIterator(this); +}; + Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { // making it explicit this property is not enumerable // because otherwise some prototype manipulation in @@ -886,9 +954,44 @@ Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { } }); +Object.defineProperty(Readable.prototype, 'readableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._readableState && this._readableState.buffer; + } +}); + +Object.defineProperty(Readable.prototype, 'readableFlowing', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._readableState.flowing; + }, + set: function (state) { + if (this._readableState) { + this._readableState.flowing = state; + } + } +}); + // exposed for testing purposes only. Readable._fromList = fromList; +Object.defineProperty(Readable.prototype, 'readableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._readableState.length; + } +}); + // Pluck off n bytes from an array of buffers. // Length is the combined lengths of all the buffers in the list. // This function is designed to be inlinable, so please take care when making @@ -900,102 +1003,20 @@ function fromList(n, state) { var ret; if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { // read it all, truncate the list - if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length); state.buffer.clear(); } else { // read part of list - ret = fromListPartial(n, state.buffer, state.decoder); + ret = state.buffer.consume(n, state.decoder); } return ret; } -// Extracts only enough buffered data to satisfy the amount requested. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function fromListPartial(n, list, hasStrings) { - var ret; - if (n < list.head.data.length) { - // slice is the same for buffers and strings - ret = list.head.data.slice(0, n); - list.head.data = list.head.data.slice(n); - } else if (n === list.head.data.length) { - // first chunk is a perfect match - ret = list.shift(); - } else { - // result spans more than one buffer - ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); - } - return ret; -} - -// Copies a specified amount of characters from the list of buffered data -// chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBufferString(n, list) { - var p = list.head; - var c = 1; - var ret = p.data; - n -= ret.length; - while (p = p.next) { - var str = p.data; - var nb = n > str.length ? str.length : n; - if (nb === str.length) ret += str;else ret += str.slice(0, n); - n -= nb; - if (n === 0) { - if (nb === str.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = str.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - -// Copies a specified amount of bytes from the list of buffered data chunks. -// This function is designed to be inlinable, so please take care when making -// changes to the function body. -function copyFromBuffer(n, list) { - var ret = Buffer.allocUnsafe(n); - var p = list.head; - var c = 1; - p.data.copy(ret); - n -= p.data.length; - while (p = p.next) { - var buf = p.data; - var nb = n > buf.length ? buf.length : n; - buf.copy(ret, ret.length - n, 0, nb); - n -= nb; - if (n === 0) { - if (nb === buf.length) { - ++c; - if (p.next) list.head = p.next;else list.head = list.tail = null; - } else { - list.head = p; - p.data = buf.slice(nb); - } - break; - } - ++c; - } - list.length -= c; - return ret; -} - function endReadable(stream) { var state = stream._readableState; - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); - + debug('endReadable', state.endEmitted); if (!state.endEmitted) { state.ended = true; pna.nextTick(endReadableNT, state, stream); @@ -1003,6 +1024,8 @@ function endReadable(stream) { } function endReadableNT(state, stream) { + debug('endReadableNT', state.endEmitted, state.length); + // Check that we didn't get one last unshift. if (!state.endEmitted && state.length === 0) { state.endEmitted = true; diff --git a/lib/_stream_transform.js b/lib/_stream_transform.js index 5d1f8b876d..0db25398ab 100644 --- a/lib/_stream_transform.js +++ b/lib/_stream_transform.js @@ -65,14 +65,15 @@ module.exports = Transform; -var Duplex = require('./_stream_duplex'); +var _require$codes = require('../errors').codes, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING, + ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0; -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ +var Duplex = require('./_stream_duplex'); -util.inherits(Transform, Duplex); +require('inherits')(Transform, Duplex); function afterTransform(er, data) { var ts = this._transformState; @@ -80,8 +81,8 @@ function afterTransform(er, data) { var cb = ts.writecb; - if (!cb) { - return this.emit('error', new Error('write callback called multiple times')); + if (cb === null) { + return this.emit('error', new ERR_MULTIPLE_CALLBACK()); } ts.writechunk = null; @@ -134,7 +135,7 @@ function Transform(options) { function prefinish() { var _this = this; - if (typeof this._flush === 'function') { + if (typeof this._flush === 'function' && !this._readableState.destroyed) { this._flush(function (er, data) { done(_this, er, data); }); @@ -159,7 +160,7 @@ Transform.prototype.push = function (chunk, encoding) { // an error, then that'll put the hurt on the whole operation. If you // never call cb(), then you'll never get another chunk. Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('_transform() is not implemented'); + cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()')); }; Transform.prototype._write = function (chunk, encoding, cb) { @@ -179,7 +180,7 @@ Transform.prototype._write = function (chunk, encoding, cb) { Transform.prototype._read = function (n) { var ts = this._transformState; - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { + if (ts.writechunk !== null && !ts.transforming) { ts.transforming = true; this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else { @@ -190,11 +191,8 @@ Transform.prototype._read = function (n) { }; Transform.prototype._destroy = function (err, cb) { - var _this2 = this; - Duplex.prototype._destroy.call(this, err, function (err2) { cb(err2); - _this2.emit('close'); }); }; @@ -204,11 +202,11 @@ function done(stream, er, data) { if (data != null) // single equals check for both `null` and `undefined` stream.push(data); + // TODO(BridgeAR): Write a test for these two error cases // if there's nothing in the write buffer, then that means // that nothing more will ever be provided - if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0'); - - if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming'); + if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0(); + if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING(); return stream.push(null); } \ No newline at end of file diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index b3f4e85a2f..b332fb0b80 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -63,11 +63,6 @@ var Duplex; Writable.WritableState = WritableState; -/**/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/**/ - /**/ var internalUtil = { deprecate: require('util-deprecate') @@ -78,9 +73,7 @@ var internalUtil = { var Stream = require('./internal/streams/stream'); /**/ -/**/ - -var Buffer = require('safe-buffer').Buffer; +var Buffer = require('buffer').Buffer; var OurUint8Array = global.Uint8Array || function () {}; function _uint8ArrayToBuffer(chunk) { return Buffer.from(chunk); @@ -89,15 +82,26 @@ function _isUint8Array(obj) { return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; } -/**/ - var destroyImpl = require('./internal/streams/destroy'); -util.inherits(Writable, Stream); +var _require = require('./internal/streams/state'), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = require('../errors').codes, + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED, + ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES, + ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END, + ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING; + +require('inherits')(Writable, Stream); function nop() {} -function WritableState(options, stream) { +function WritableState(options, stream, isDuplex) { Duplex = Duplex || require('./_stream_duplex'); options = options || {}; @@ -107,7 +111,7 @@ function WritableState(options, stream) { // However, some cases require setting options to different // values for the readable and the writable sides of the duplex stream. // These options can be provided separately as readableXXX and writableXXX. - var isDuplex = stream instanceof Duplex; + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream // contains buffers or objects. @@ -118,14 +122,7 @@ function WritableState(options, stream) { // the point at which write() starts returning false // Note: 0 is a valid value, means that we always return false if // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var writableHwm = options.writableHighWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - - if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; - - // cast to ints. - this.highWaterMark = Math.floor(this.highWaterMark); + this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called this.finalCalled = false; @@ -200,6 +197,9 @@ function WritableState(options, stream) { // True if the error was already emitted and should not be thrown again this.errorEmitted = false; + // Should close be emitted on destroy. Defaults to true. + this.emitClose = options.emitClose !== false; + // count buffered requests this.bufferedRequestCount = 0; @@ -221,7 +221,7 @@ WritableState.prototype.getBuffer = function getBuffer() { (function () { try { Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { + get: internalUtil.deprecate(function writableStateBufferGetter() { return this.getBuffer(); }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') }); @@ -257,11 +257,14 @@ function Writable(options) { // Trying to use the custom `instanceof` for Writable here will also break the // Node.js LazyTransform implementation, which has a non-trivial getter for // `_writableState` that would lead to infinite recursion. - if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { - return new Writable(options); - } - this._writableState = new WritableState(options, this); + // Checking for a Stream.Duplex instance is faster here instead of inside + // the WritableState constructor, at least with V8 6.5 + var isDuplex = this instanceof Duplex; + + if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options); + + this._writableState = new WritableState(options, this, isDuplex); // legacy. this.writable = true; @@ -281,11 +284,11 @@ function Writable(options) { // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); + this.emit('error', new ERR_STREAM_CANNOT_PIPE()); }; function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); + var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb stream.emit('error', er); pna.nextTick(cb, er); @@ -295,20 +298,19 @@ function writeAfterEnd(stream, cb) { // mode the stream is in. Currently this means that `null` is never accepted // and undefined/non-string values are only allowed in object mode. function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; + var er; if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); + er = new ERR_STREAM_NULL_VALUES(); + } else if (typeof chunk !== 'string' && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); } if (er) { stream.emit('error', er); pna.nextTick(cb, er); - valid = false; + return false; } - return valid; + return true; } Writable.prototype.write = function (chunk, encoding, cb) { @@ -329,7 +331,7 @@ Writable.prototype.write = function (chunk, encoding, cb) { if (typeof cb !== 'function') cb = nop; - if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { state.pendingcb++; ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); } @@ -338,9 +340,7 @@ Writable.prototype.write = function (chunk, encoding, cb) { }; Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; + this._writableState.corked++; }; Writable.prototype.uncork = function () { @@ -349,18 +349,28 @@ Writable.prototype.uncork = function () { if (state.corked) { state.corked--; - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); } }; Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { // node::ParseEncoding() requires lower case. if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding); this._writableState.defaultEncoding = encoding; return this; }; +Object.defineProperty(Writable.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState && this._writableState.getBuffer(); + } +}); + function decodeChunk(state, chunk, encoding) { if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { chunk = Buffer.from(chunk, encoding); @@ -425,7 +435,7 @@ function doWrite(stream, state, writev, len, chunk, encoding, cb) { state.writecb = cb; state.writing = true; state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); state.sync = false; } @@ -465,6 +475,8 @@ function onwrite(stream, er) { var sync = state.sync; var cb = state.writecb; + if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK(); + onwriteStateUpdate(state); if (er) onwriteError(stream, state, sync, er, cb);else { @@ -565,7 +577,7 @@ function clearBuffer(stream, state) { } Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('_write() is not implemented')); + cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()')); }; Writable.prototype._writev = null; @@ -591,9 +603,21 @@ Writable.prototype.end = function (chunk, encoding, cb) { } // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); + if (!state.ending) endWritable(this, state, cb); + + return this; }; +Object.defineProperty(Writable.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.length; + } +}); + function needFinish(state) { return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; } @@ -610,7 +634,7 @@ function callFinal(stream, state) { } function prefinish(stream, state) { if (!state.prefinished && !state.finalCalled) { - if (typeof stream._final === 'function') { + if (typeof stream._final === 'function' && !state.destroyed) { state.pendingcb++; state.finalCalled = true; pna.nextTick(callFinal, stream, state); @@ -652,14 +676,16 @@ function onCorkedFinish(corkReq, state, err) { cb(err); entry = entry.next; } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = corkReq; - } else { - state.corkedRequestsFree = corkReq; - } + + // reuse the free corkReq. + state.corkedRequestsFree.next = corkReq; } Object.defineProperty(Writable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, get: function () { if (this._writableState === undefined) { return false; @@ -682,6 +708,5 @@ Object.defineProperty(Writable.prototype, 'destroyed', { Writable.prototype.destroy = destroyImpl.destroy; Writable.prototype._undestroy = destroyImpl.undestroy; Writable.prototype._destroy = function (err, cb) { - this.end(); cb(err); }; \ No newline at end of file diff --git a/lib/internal/streams/BufferList.js b/lib/internal/streams/BufferList.js deleted file mode 100644 index aefc68bd90..0000000000 --- a/lib/internal/streams/BufferList.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var Buffer = require('safe-buffer').Buffer; -var util = require('util'); - -function copyBuffer(src, target, offset) { - src.copy(target, offset); -} - -module.exports = function () { - function BufferList() { - _classCallCheck(this, BufferList); - - this.head = null; - this.tail = null; - this.length = 0; - } - - BufferList.prototype.push = function push(v) { - var entry = { data: v, next: null }; - if (this.length > 0) this.tail.next = entry;else this.head = entry; - this.tail = entry; - ++this.length; - }; - - BufferList.prototype.unshift = function unshift(v) { - var entry = { data: v, next: this.head }; - if (this.length === 0) this.tail = entry; - this.head = entry; - ++this.length; - }; - - BufferList.prototype.shift = function shift() { - if (this.length === 0) return; - var ret = this.head.data; - if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; - --this.length; - return ret; - }; - - BufferList.prototype.clear = function clear() { - this.head = this.tail = null; - this.length = 0; - }; - - BufferList.prototype.join = function join(s) { - if (this.length === 0) return ''; - var p = this.head; - var ret = '' + p.data; - while (p = p.next) { - ret += s + p.data; - }return ret; - }; - - BufferList.prototype.concat = function concat(n) { - if (this.length === 0) return Buffer.alloc(0); - if (this.length === 1) return this.head.data; - var ret = Buffer.allocUnsafe(n >>> 0); - var p = this.head; - var i = 0; - while (p) { - copyBuffer(p.data, ret, i); - i += p.data.length; - p = p.next; - } - return ret; - }; - - return BufferList; -}(); - -if (util && util.inspect && util.inspect.custom) { - module.exports.prototype[util.inspect.custom] = function () { - var obj = util.inspect({ length: this.length }); - return this.constructor.name + ' ' + obj; - }; -} \ No newline at end of file diff --git a/lib/internal/streams/async_iterator.js b/lib/internal/streams/async_iterator.js new file mode 100644 index 0000000000..4ec9f1ac3d --- /dev/null +++ b/lib/internal/streams/async_iterator.js @@ -0,0 +1,179 @@ +'use strict'; + +/**/ + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var pna = require('process-nextick-args'); +/**/ + +var kLastResolve = Symbol('lastResolve'); +var kLastReject = Symbol('lastReject'); +var kError = Symbol('error'); +var kEnded = Symbol('ended'); +var kLastPromise = Symbol('lastPromise'); +var kHandlePromise = Symbol('handlePromise'); +var kStream = Symbol('stream'); + +var AsyncIteratorRecord = function AsyncIteratorRecord(value, done) { + _classCallCheck(this, AsyncIteratorRecord); + + this.done = done; + this.value = value; +}; + +function readAndResolve(iter) { + var resolve = iter[kLastResolve]; + if (resolve !== null) { + var data = iter[kStream].read(); + // we defer if data is null + // we can be expecting either 'end' or + // 'error' + if (data !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + resolve(new AsyncIteratorRecord(data, false)); + } + } +} + +function onReadable(iter) { + // we wait for the next tick, because it might + // emit an error with process.nextTick + pna.nextTick(readAndResolve, iter); +} + +function onEnd(iter) { + var resolve = iter[kLastResolve]; + if (resolve !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + resolve(new AsyncIteratorRecord(null, true)); + } + iter[kEnded] = true; +} + +function onError(iter, err) { + var reject = iter[kLastReject]; + // reject if we are waiting for data in the Promise + // returned by next() and store the error + if (reject !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + reject(err); + } + iter[kError] = err; +} + +function wrapForNext(lastPromise, iter) { + return function (resolve, reject) { + lastPromise.then(function () { + iter[kHandlePromise](resolve, reject); + }, reject); + }; +} + +var ReadableAsyncIterator = function () { + function ReadableAsyncIterator(stream) { + var _this = this; + + _classCallCheck(this, ReadableAsyncIterator); + + this[kStream] = stream; + this[kLastResolve] = null; + this[kLastReject] = null; + this[kError] = null; + this[kEnded] = false; + this[kLastPromise] = null; + + stream.on('readable', onReadable.bind(null, this)); + stream.on('end', onEnd.bind(null, this)); + stream.on('error', onError.bind(null, this)); + + // the function passed to new Promise + // is cached so we avoid allocating a new + // closure at every run + this[kHandlePromise] = function (resolve, reject) { + var data = _this[kStream].read(); + if (data) { + _this[kLastPromise] = null; + _this[kLastResolve] = null; + _this[kLastReject] = null; + resolve(new AsyncIteratorRecord(data, false)); + } else { + _this[kLastResolve] = resolve; + _this[kLastReject] = reject; + } + }; + } + + ReadableAsyncIterator.prototype.next = function next() { + // if we have detected an error in the meanwhile + // reject straight away + var error = this[kError]; + if (error !== null) { + return Promise.reject(error); + } + + if (this[kEnded]) { + return Promise.resolve(new AsyncIteratorRecord(null, true)); + } + + // if we have multiple next() calls + // we will wait for the previous Promise to finish + // this logic is optimized to support for await loops, + // where next() is only called once at a time + var lastPromise = this[kLastPromise]; + var promise = void 0; + + if (lastPromise) { + promise = new Promise(wrapForNext(lastPromise, this)); + } else { + // fast path needed to support multiple this.push() + // without triggering the next() queue + var data = this[kStream].read(); + if (data !== null) { + return Promise.resolve(new AsyncIteratorRecord(data, false)); + } + + promise = new Promise(this[kHandlePromise]); + } + + this[kLastPromise] = promise; + + return promise; + }; + + ReadableAsyncIterator.prototype.return = function _return() { + var _this2 = this; + + // destroy(err, cb) is a private API + // we can guarantee we have that here, because we control the + // Readable class this is attached to + return new Promise(function (resolve, reject) { + _this2[kStream].destroy(null, function (err) { + if (err) { + reject(err); + return; + } + resolve(new AsyncIteratorRecord(null, true)); + }); + }); + }; + + _createClass(ReadableAsyncIterator, [{ + key: 'stream', + get: function () { + return this[kStream]; + } + }]); + + return ReadableAsyncIterator; +}(); + +module.exports = ReadableAsyncIterator; \ No newline at end of file diff --git a/lib/internal/streams/buffer_list.js b/lib/internal/streams/buffer_list.js new file mode 100644 index 0000000000..72463e17ff --- /dev/null +++ b/lib/internal/streams/buffer_list.js @@ -0,0 +1,168 @@ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Buffer = require('buffer').Buffer; +var util = require('util'); + +var _require = require('util'), + inspect = _require.inspect; + +function copyBuffer(src, target, offset) { + src.copy(target, offset); +} + +module.exports = function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + BufferList.prototype.push = function push(v) { + var entry = { data: v, next: null }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + }; + + BufferList.prototype.unshift = function unshift(v) { + var entry = { data: v, next: this.head }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + }; + + BufferList.prototype.shift = function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + }; + + BufferList.prototype.clear = function clear() { + this.head = this.tail = null; + this.length = 0; + }; + + BufferList.prototype.join = function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + while (p = p.next) { + ret += s + p.data; + }return ret; + }; + + BufferList.prototype.concat = function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; + } + return ret; + }; + + // Consumes a specified amount of bytes or characters from the buffered data. + + + BufferList.prototype.consume = function consume(n, hasStrings) { + var ret; + if (n < this.head.data.length) { + // `slice` is the same for buffers and strings. + ret = this.head.data.slice(0, n); + this.head.data = this.head.data.slice(n); + } else if (n === this.head.data.length) { + // First chunk is a perfect match. + ret = this.shift(); + } else { + // Result spans more than one buffer. + ret = hasStrings ? this._getString(n) : this._getBuffer(n); + } + return ret; + }; + + BufferList.prototype.first = function first() { + return this.head.data; + }; + + // Consumes a specified amount of characters from the buffered data. + + + BufferList.prototype._getString = function _getString(n) { + var p = this.head; + var c = 1; + var ret = p.data; + n -= ret.length; + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = str.slice(nb); + } + break; + } + ++c; + } + this.length -= c; + return ret; + }; + + // Consumes a specified amount of bytes from the buffered data. + + + BufferList.prototype._getBuffer = function _getBuffer(n) { + var ret = Buffer.allocUnsafe(n); + var p = this.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = buf.slice(nb); + } + break; + } + ++c; + } + this.length -= c; + return ret; + }; + + BufferList.prototype[inspect.custom] = function () { + var obj = inspect({ length: this.length }); + return this.constructor.name + ' ' + obj; + }; + + return BufferList; +}(); + +if (util && util.inspect && util.inspect.custom) { + module.exports.prototype[util.inspect.custom] = function () { + var obj = util.inspect({ length: this.length }); + return this.constructor.name + ' ' + obj; + }; +} \ No newline at end of file diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 5a0a0d88ce..ca929a153c 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -35,18 +35,32 @@ function destroy(err, cb) { this._destroy(err || null, function (err) { if (!cb && err) { - pna.nextTick(emitErrorNT, _this, err); + pna.nextTick(emitErrorAndCloseNT, _this, err); if (_this._writableState) { _this._writableState.errorEmitted = true; } } else if (cb) { + pna.nextTick(emitCloseNT, _this); cb(err); + } else { + pna.nextTick(emitCloseNT, _this); } }); return this; } +function emitErrorAndCloseNT(self, err) { + emitErrorNT(self, err); + emitCloseNT(self); +} + +function emitCloseNT(self) { + if (self._writableState && !self._writableState.emitClose) return; + if (self._readableState && !self._readableState.emitClose) return; + self.emit('close'); +} + function undestroy() { if (this._readableState) { this._readableState.destroyed = false; @@ -59,6 +73,8 @@ function undestroy() { this._writableState.destroyed = false; this._writableState.ended = false; this._writableState.ending = false; + this._writableState.finalCalled = false; + this._writableState.prefinished = false; this._writableState.finished = false; this._writableState.errorEmitted = false; } diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js new file mode 100644 index 0000000000..b06dabdb93 --- /dev/null +++ b/lib/internal/streams/end-of-stream.js @@ -0,0 +1,99 @@ +// Ported from https://github.com/mafintosh/end-of-stream with +// permission from the author, Mathias Buus (@mafintosh). + +'use strict'; + +/**/ + +var pna = require('process-nextick-args'); +/**/ + +var ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE; + +function noop() {} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function once(callback) { + var called = false; + return function (err) { + if (called) return; + called = true; + callback.call(this, err); + }; +} + +function eos(stream, opts, callback) { + if (typeof opts === 'function') return eos(stream, null, opts); + if (!opts) opts = {}; + + callback = once(callback || noop); + + var ws = stream._writableState; + var rs = stream._readableState; + var readable = opts.readable || opts.readable !== false && stream.readable; + var writable = opts.writable || opts.writable !== false && stream.writable; + + var onlegacyfinish = function () { + if (!stream.writable) onfinish(); + }; + + var onfinish = function () { + writable = false; + if (!readable) callback.call(stream); + }; + + var onend = function () { + readable = false; + if (!writable) callback.call(stream); + }; + + var onerror = function (err) { + callback.call(stream, err); + }; + + var onclose = function () { + if (readable && !(rs && rs.ended)) { + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + } + if (writable && !(ws && ws.ended)) { + return callback.call(stream, new ERR_STREAM_PREMATURE_CLOSE()); + } + }; + + var onrequest = function () { + stream.req.on('finish', onfinish); + }; + + if (isRequest(stream)) { + stream.on('complete', onfinish); + stream.on('abort', onclose); + if (stream.req) onrequest();else stream.on('request', onrequest); + } else if (writable && !ws) { + // legacy streams + stream.on('end', onlegacyfinish); + stream.on('close', onlegacyfinish); + } + + stream.on('end', onend); + stream.on('finish', onfinish); + if (opts.error !== false) stream.on('error', onerror); + stream.on('close', onclose); + + return function () { + stream.removeListener('complete', onfinish); + stream.removeListener('abort', onclose); + stream.removeListener('request', onrequest); + if (stream.req) stream.req.removeListener('finish', onfinish); + stream.removeListener('end', onlegacyfinish); + stream.removeListener('close', onlegacyfinish); + stream.removeListener('finish', onfinish); + stream.removeListener('end', onend); + stream.removeListener('error', onerror); + stream.removeListener('close', onclose); + }; +} + +module.exports = eos; \ No newline at end of file diff --git a/lib/internal/streams/pipeline.js b/lib/internal/streams/pipeline.js new file mode 100644 index 0000000000..c23ce4e3a5 --- /dev/null +++ b/lib/internal/streams/pipeline.js @@ -0,0 +1,107 @@ +// Ported from https://github.com/mafintosh/pump with +// permission from the author, Mathias Buus (@mafintosh). + +'use strict'; + +/**/ + +var pna = require('process-nextick-args'); +/**/ + +var eos = void 0; + +var _require$codes = require('../../../errors').codes, + ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED; + +function once(callback) { + var called = false; + return function (err) { + if (called) return; + called = true; + callback(err); + }; +} + +function noop(err) { + // Rethrow the error if it exists to avoid swallowing it + if (err) throw err; +} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function destroyer(stream, reading, writing, callback) { + callback = once(callback); + + var closed = false; + stream.on('close', function () { + closed = true; + }); + + if (eos === undefined) eos = require('./end-of-stream'); + eos(stream, { readable: reading, writable: writing }, function (err) { + if (err) return callback(err); + closed = true; + callback(); + }); + + var destroyed = false; + return function (err) { + if (closed) return; + if (destroyed) return; + destroyed = true; + + // request.destroy just do .end - .abort is what we want + if (isRequest(stream)) return stream.abort(); + if (typeof stream.destroy === 'function') return stream.destroy(); + + callback(err || new ERR_STREAM_DESTROYED('pipe')); + }; +} + +function call(fn) { + fn(); +} + +function pipe(from, to) { + return from.pipe(to); +} + +function popCallback(streams) { + if (!streams.length) return noop; + if (typeof streams[streams.length - 1] !== 'function') return noop; + return streams.pop(); +} + +function pipeline() { + for (var _len = arguments.length, streams = Array(_len), _key = 0; _key < _len; _key++) { + streams[_key] = arguments[_key]; + } + + var callback = popCallback(streams); + + if (Array.isArray(streams[0])) streams = streams[0]; + + if (streams.length < 2) { + throw new ERR_MISSING_ARGS('streams'); + } + + var error = void 0; + var destroys = streams.map(function (stream, i) { + var reading = i < streams.length - 1; + var writing = i > 0; + return destroyer(stream, reading, writing, function (err) { + if (!error) error = err; + if (err) destroys.forEach(call); + if (reading) return; + destroys.forEach(call); + callback(error); + }); + }); + + return streams.reduce(pipe); +} + +module.exports = pipeline; \ No newline at end of file diff --git a/lib/internal/streams/state.js b/lib/internal/streams/state.js new file mode 100644 index 0000000000..1632e883f8 --- /dev/null +++ b/lib/internal/streams/state.js @@ -0,0 +1,30 @@ +'use strict'; + +/**/ + +var pna = require('process-nextick-args'); +/**/ + +var ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE; + +function highWaterMarkFrom(options, isDuplex, duplexKey) { + return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null; +} + +function getHighWaterMark(state, options, duplexKey, isDuplex) { + var hwm = highWaterMarkFrom(options, isDuplex, duplexKey); + if (hwm != null) { + if (!Number.isInteger(hwm) || hwm < 0) { + var name = isDuplex ? duplexKey : 'highWaterMark'; + throw new ERR_INVALID_OPT_VALUE(name, hwm); + } + return Math.floor(hwm); + } + + // Default value + return state.objectMode ? 16 : 16 * 1024; +} + +module.exports = { + getHighWaterMark: getHighWaterMark +}; \ No newline at end of file diff --git a/package.json b/package.json index dbb1da6be5..cd89cc438e 100644 --- a/package.json +++ b/package.json @@ -1,31 +1,57 @@ { "name": "readable-stream", - "version": "2.3.6", + "version": "3.0.0-rc.3", "description": "Streams3, a user-land copy of the stream library from Node.js", "main": "readable.js", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "process-nextick-args": "^2.0.0", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "devDependencies": { + "airtap": "0.0.9", "assert": "^1.4.0", + "babel-cli": "^6.26.0", + "babel-core": "^6.26.3", + "babel-plugin-transform-async-generator-functions": "^6.24.1", + "babel-plugin-transform-async-to-generator": "^6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "^6.5.2", + "babel-plugin-transform-es2015-block-scoping": "^6.26.0", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", + "babel-plugin-transform-es2015-destructuring": "^6.18.0", + "babel-plugin-transform-es2015-for-of": "^6.8.0", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.8.0", + "babel-plugin-transform-inline-imports-commonjs": "^1.2.0", "babel-polyfill": "^6.9.1", - "buffer": "^4.9.0", - "lolex": "^2.3.2", - "nyc": "^6.4.0", - "tap": "^0.7.0", - "tape": "^4.8.0" + "babel-preset-env": "^1.7.0", + "bl": "^2.0.0", + "buffer": "^5.1.0", + "deep-strict-equal": "^0.2.0", + "glob": "^7.1.2", + "gunzip-maybe": "^1.4.1", + "hyperquest": "^2.1.3", + "lolex": "^2.6.0", + "nyc": "^11.0.0", + "pump": "^3.0.0", + "rimraf": "^2.6.2", + "tap": "^11.0.0", + "tape": "^4.9.0", + "tar-fs": "^1.16.2", + "util-promisify": "^2.1.0" }, "scripts": { - "test": "tap test/parallel/*.js test/ours/*.js && node test/verify-dependencies.js", - "ci": "tap test/parallel/*.js test/ours/*.js --tap | tee test.tap && node test/verify-dependencies.js", + "test": "tap -j 4 test/parallel/*.js test/ours/*.js", + "ci": "TAP=1 tap test/parallel/*.js test/ours/*.js | tee test.tap", + "test-browsers": "airtap --sauce-connect --loopback airtap.local -- test/browser.js", + "test-browser-local": "airtap --local -- test/browser.js", "cover": "nyc npm test", - "report": "nyc report --reporter=lcov" + "report": "nyc report --reporter=lcov", + "update-browser-errors": "babel --presets env -o errors-browser.js errors.js" }, "repository": { "type": "git", @@ -38,9 +64,9 @@ ], "browser": { "util": false, + "worker_threads": false, + "./errors": "./errors-browser.js", "./readable.js": "./readable-browser.js", - "./writable.js": "./writable-browser.js", - "./duplex.js": "./duplex-browser.js", "./lib/internal/streams/stream.js": "./lib/internal/streams/stream-browser.js" }, "nyc": { diff --git a/passthrough.js b/passthrough.js deleted file mode 100644 index ffd791d7ff..0000000000 --- a/passthrough.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./readable').PassThrough diff --git a/readable.js b/readable.js index ec89ec5330..aeec0df5b3 100644 --- a/readable.js +++ b/readable.js @@ -16,4 +16,6 @@ if (process.env.READABLE_STREAM === 'disable' && Stream) { exports.Duplex = require('./lib/_stream_duplex.js'); exports.Transform = require('./lib/_stream_transform.js'); exports.PassThrough = require('./lib/_stream_passthrough.js'); + exports.finished = require('./lib/internal/streams/end-of-stream.js'); + exports.pipeline = require('./lib/internal/streams/pipeline.js'); } diff --git a/test/browser.js b/test/browser.js index a82c13ae34..a3504d63f7 100644 --- a/test/browser.js +++ b/test/browser.js @@ -11,6 +11,27 @@ if (!global.console.info) { global.console.info = global.console.log; } var test = require('tape'); +var util = require('util'); + +// TODO: add replacements instead +if (!util.inspect) { + util.inspect = function () {}; + util.inspect.custom = 'custom'; +} + +// TODO: add replacements instead +global.process = { + env: {}, + on: function () {}, + cwd: function () { + return '/'; + }, + binding: function () { + return { + hasTracing: false + }; + } +}; test('streams', function (t) { require('./browser/test-stream-big-packet')(t); @@ -49,8 +70,8 @@ test('streams 2', function (t) { require('./browser/test-stream2-pipe-error-once-listener')(t); require('./browser/test-stream2-push')(t); require('./browser/test-stream2-readable-empty-buffer-no-eof')(t); - require('./browser/test-stream2-readable-from-list')(t); - require('./browser/test-stream2-transform')(t); + // require('./browser/test-stream2-readable-from-list')(t); + // require('./browser/test-stream2-transform')(t); require('./browser/test-stream2-set-encoding')(t); require('./browser/test-stream2-readable-legacy-drain')(t); require('./browser/test-stream2-readable-wrap-empty')(t); diff --git a/test/common/README.md b/test/common/README.md index 67e4e4e48f..943700ed71 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -2,19 +2,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) exports[i] = util[i]; - /**//**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -# Node.js Core Test Common Modules + /**/# Node.js Core Test Common Modules This directory contains modules used to test the Node.js implementation. @@ -26,6 +14,10 @@ This directory contains modules used to test the Node.js implementation. * [DNS module](#dns-module) * [Duplex pair helper](#duplex-pair-helper) * [Fixtures module](#fixtures-module) +* [Heap dump checker module](#heap-dump-checker-module) +* [HTTP2 module](#http2-module) +* [Internet module](#internet-module) +* [tmpdir module](#tmpdir-module) * [WPT module](#wpt-module) ## Benchmark Module @@ -34,7 +26,7 @@ The `benchmark` module is used by tests to run benchmarks. ### runBenchmark(name, args, env) -* `name` [<String>] Name of benchmark suite to be run. +* `name` [<string>] Name of benchmark suite to be run. * `args` [<Array>] Array of environment variable key/value pairs (ex: `n=1`) to be applied via `--set`. * `env` [<Object>] Environment variables to be applied during the run. @@ -54,12 +46,12 @@ Takes `whitelist` and concats that with predefined `knownGlobals`. A stream to push an array into a REPL ### busyLoop(time) -* `time` [<Number>] +* `time` [<number>] Blocks for `time` amount of time. ### canCreateSymLink() -* return [<Boolean>] +* return [<boolean>] Checks whether the current running process can create symlinks. On Windows, this returns `false` if the process running doesn't have privileges to create @@ -67,20 +59,21 @@ symlinks ([SeCreateSymbolicLinkPrivilege](https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx)). On non-Windows platforms, this always returns `true`. -### crashOnUnhandledRejection() - -Installs a `process.on('unhandledRejection')` handler that crashes the process -after a tick. This is useful for tests that use Promises and need to make sure -no unexpected rejections occur, because currently they result in silent -failures. - ### ddCommand(filename, kilobytes) * return [<Object>] Platform normalizes the `dd` command +### disableCrashOnUnhandledRejection() + +Removes the `process.on('unhandledRejection')` handler that crashes the process +after a tick. The handler is useful for tests that use Promises and need to make +sure no unexpected rejections occur, because currently they result in silent +failures. However, it is useful in some rare cases to disable it, for example if +the `unhandledRejection` hook is directly used by the test. + ### enoughTestMem -* [<Boolean>] +* [<boolean>] Indicates if there is more than 1gb of total memory. @@ -89,17 +82,19 @@ Indicates if there is more than 1gb of total memory. * `settings` [<Object>] that must contain the `code` property plus any of the other following properties (some properties only apply for `AssertionError`): - * `code` [<String>] + * `code` [<string>] expected error must have this value for its `code` property. * `type` [<Function>] expected error must be an instance of `type` and must be an Error subclass. - * `message` [<String>] or [<RegExp>] + * `message` [<string>] or [<RegExp>] if a string is provided for `message`, expected error must have it for its `message` property; if a regular expression is provided for `message`, the regular expression must match the `message` property of the expected error. - * `name` [<String>] + * `name` [<string>] expected error must have this value for its `name` property. - * `generatedMessage` [<String>] + * `info` <Object> expected error must have the same `info` property + that is deeply equal to this value. + * `generatedMessage` [<string>] (`AssertionError` only) expected error must have this value for its `generatedMessage` property. * `actual` <any> @@ -111,7 +106,7 @@ Indicates if there is more than 1gb of total memory. * `operator` <any> (`AssertionError` only) expected error must have this value for its `operator` property. -* `exact` [<Number>] default = 1 +* `exact` [<number>] default = 1 * return [<Function>] If `fn` is provided, it will be passed to `assert.throws` as first argument @@ -121,15 +116,18 @@ Indicates if there is more than 1gb of total memory. returned function has not been called exactly `exact` number of times when the test is complete, then the test will fail. -### expectWarning(name, expected) -* `name` [<String>] -* `expected` [<String>] | [<Array>] +### expectWarning(name, expected, code) +* `name` [<string>] +* `expected` [<string>] | [<Array>] +* `code` [<string>] -Tests whether `name` and `expected` are part of a raised warning. +Tests whether `name`, `expected`, and `code` are part of a raised warning. If +an expected warning does not have a code then `common.noWarnCode` can be used +to indicate this. ### fileExists(pathname) -* pathname [<String>] -* return [<Boolean>] +* pathname [<string>] +* return [<boolean>] Checks if `pathname` exists @@ -139,44 +137,52 @@ Checks if `pathname` exists Returns an instance of all possible `ArrayBufferView`s of the provided Buffer. +### getBufferSources(buf) +* `buf` [<Buffer>] +* return [<BufferSource[]>] + +Returns an instance of all possible `BufferSource`s of the provided Buffer, +consisting of all `ArrayBufferView` and an `ArrayBuffer`. + ### getCallSite(func) * `func` [<Function>] -* return [<String>] +* return [<string>] Returns the file name and line number for the provided Function. -### globalCheck -* [<Boolean>] +### getTTYfd() + +Attempts to get a valid TTY file descriptor. Returns `-1` if it fails. -Set to `false` if the test should not check for global leaks. +The TTY file descriptor is assumed to be capable of being writable. ### hasCrypto -* [<Boolean>] +* [<boolean>] Indicates whether OpenSSL is available. ### hasFipsCrypto -* [<Boolean>] +* [<boolean>] Indicates `hasCrypto` and `crypto` with fips. ### hasIntl -* [<Boolean>] +* [<boolean>] Indicates if [internationalization] is supported. ### hasSmallICU -* [<Boolean>] +* [<boolean>] Indicates `hasIntl` and `small-icu` are supported. ### hasIPv6 -* [<Boolean>] +* [<boolean>] Indicates whether `IPv6` is supported on this platform. ### hasMultiLocalhost -* [<Boolean>] +* [<boolean>] Indicates if there are multiple localhosts available. @@ -199,63 +205,68 @@ be passed to `listener`. What's more, `process.stdout.writeTimes` is a count of the number of calls. ### inFreeBSDJail -* [<Boolean>] +* [<boolean>] Checks whether free BSD Jail is true or false. ### isAIX -* [<Boolean>] +* [<boolean>] Platform check for Advanced Interactive eXecutive (AIX). ### isAlive(pid) -* `pid` [<Number>] -* return [<Boolean>] +* `pid` [<number>] +* return [<boolean>] Attempts to 'kill' `pid` ### isFreeBSD -* [<Boolean>] +* [<boolean>] Platform check for Free BSD. ### isLinux -* [<Boolean>] +* [<boolean>] Platform check for Linux. ### isLinuxPPCBE -* [<Boolean>] +* [<boolean>] Platform check for Linux on PowerPC. ### isOSX -* [<Boolean>] +* [<boolean>] Platform check for macOS. ### isSunOS -* [<Boolean>] +* [<boolean>] Platform check for SunOS. ### isWindows -* [<Boolean>] +* [<boolean>] Platform check for Windows. ### isWOW64 -* [<Boolean>] +* [<boolean>] Platform check for Windows 32-bit on Windows 64-bit. +### isCPPSymbolsNotMapped +* [<boolean>] + +Platform check for C++ symbols are mapped or not. + ### leakedGlobals() * return [<Array>] Indicates whether any globals are not on the `knownGlobals` list. ### localhostIPv4 -* [<String>] +* [<string>] IP of `localhost`. @@ -266,7 +277,7 @@ Array of IPV6 representations for `localhost`. ### mustCall([fn][, exact]) * `fn` [<Function>] default = () => {} -* `exact` [<Number>] default = 1 +* `exact` [<number>] default = 1 * return [<Function>] Returns a function that calls `fn`. If the returned function has not been called @@ -275,9 +286,20 @@ fail. If `fn` is not provided, an empty function will be used. +### mustCallAsync([fn][, exact]) +* `fn` [<Function>] +* `exact` [<number>] default = 1 +* return [<Function>] + +The same as `mustCall()`, except that it is also checked that the Promise +returned by the function is fulfilled for each invocation of the function. + +The return value of the wrapped function is the return value of the original +function, if necessary wrapped as a promise. + ### mustCallAtLeast([fn][, minimum]) * `fn` [<Function>] default = () => {} -* `minimum` [<Number>] default = 1 +* `minimum` [<number>] default = 1 * return [<Function>] Returns a function that calls `fn`. If the returned function has not been called @@ -287,52 +309,65 @@ fail. If `fn` is not provided, an empty function will be used. ### mustNotCall([msg]) -* `msg` [<String>] default = 'function should not have been called' +* `msg` [<string>] default = 'function should not have been called' * return [<Function>] Returns a function that triggers an `AssertionError` if it is invoked. `msg` is used as the error message for the `AssertionError`. ### nodeProcessAborted(exitCode, signal) -* `exitCode` [<Number>] -* `signal` [<String>] -* return [<Boolean>] +* `exitCode` [<number>] +* `signal` [<string>] +* return [<boolean>] 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. +### noWarnCode +See `common.expectWarning()` for usage. + +### onGC(target, listener) +* `target` [<Object>] +* `listener` [<Object>] + * `ongc` [<Function>] + +Installs a GC listener for the collection of `target`. + +This uses `async_hooks` for GC tracking. This means that it enables +`async_hooks` tracking, which may affect the test functionality. It also +means that between a `global.gc()` call and the listener being invoked +a full `setImmediate()` invocation passes. + +`listener` is an object to make it easier to use a closure; the target object +should not be in scope when `listener.ongc()` is created. + ### opensslCli -* [<Boolean>] +* [<boolean>] Indicates whether 'opensslCli' is supported. ### platformTimeout(ms) -* `ms` [<Number>] -* return [<Number>] +* `ms` [<number>] +* return [<number>] Platform normalizes timeout. ### PIPE -* [<String>] +* [<string>] Path to the test socket. ### PORT -* [<Number>] +* [<number>] A port number for tests to use if one is needed. ### printSkipMessage(msg) -* `msg` [<String>] +* `msg` [<string>] Logs '1..0 # Skipped: ' + `msg` -### refreshTmpDir() -* return [<String>] - -Deletes the testing 'tmp' directory and recreates it. - ### restoreStderr() Restore the original `process.stderr.write`. Used to restore `stderr` to its @@ -344,17 +379,20 @@ Restore the original `process.stdout.write`. Used to restore `stdout` to its original state after calling [`common.hijackStdOut()`][]. ### rootDir -* [<String>] +* [<string>] Path to the 'root' directory. either `/` or `c:\\` (windows) -### projectDir -* [<String>] +### runWithInvalidFD(func) +* `func` [<Function>] -Path to the project directory. +Runs `func` with an invalid file descriptor that is an unsigned integer and +can be used to trigger `EBADF` as the first argument. If no such file +descriptor could be generated, a skip message will be printed and the `func` +will not be run. ### skip(msg) -* `msg` [<String>] +* `msg` [<string>] Logs '1..0 # Skipped: ' + `msg` and exits with exit code `0`. @@ -385,19 +423,14 @@ Platform normalizes the `pwd` command. Synchronous version of `spawnPwd`. -### tmpDir -* [<String>] - -The realpath of the 'tmp' directory. - ## Countdown Module The `Countdown` module provides a simple countdown mechanism for tests that require a particular action to be taken after a given number of completed tasks (for instance, shutting down an HTTP server after a specific number of -requests). +requests). The Countdown will fail the test if the remainder did not reach 0. - + ```js const Countdown = require('../common/countdown'); @@ -428,12 +461,30 @@ called before the callback is invoked. ## DNS Module -The `DNS` module provides a naïve DNS parser/serializer. +The `DNS` module provides utilities related to the `dns` built-in module. + +### errorLookupMock(code, syscall) + +* `code` [<string>] Defaults to `dns.mockedErrorCode`. +* `syscall` [<string>] Defaults to `dns.mockedSysCall`. +* return [<Function>] + +A mock for the `lookup` option of `net.connect()` that would result in an error +with the `code` and the `syscall` specified. Returns a function that has the +same signature as `dns.lookup()`. + +### mockedErrorCode + +The default `code` of errors generated by `errorLookupMock`. + +### mockedSysCall + +The default `syscall` of errors generated by `errorLookupMock`. ### readDomainFromPacket(buffer, offset) * `buffer` [<Buffer>] -* `offset` [<Number>] +* `offset` [<number>] * return [<Object>] Reads the domain string from a packet and returns an object containing the @@ -449,14 +500,14 @@ the packet depending on the type of packet. ### writeIPv6(ip) -* `ip` [<String>] +* `ip` [<string>] * return [<Buffer>] Reads an IPv6 String and returns a Buffer containing the parts. ### writeDomainName(domain) -* `domain` [<String>] +* `domain` [<string>] * return [<Buffer>] Reads a Domain String and returns a Buffer containing the domain. @@ -484,30 +535,224 @@ files in the `test/fixtures` directory. ### fixtures.fixturesDir -* [<String>] +* [<string>] The absolute path to the `test/fixtures/` directory. ### fixtures.path(...args) -* `...args` [<String>] +* `...args` [<string>] Returns the result of `path.join(fixtures.fixturesDir, ...args)`. ### fixtures.readSync(args[, enc]) -* `args` [<String>] | [<Array>] +* `args` [<string>] | [<Array>] Returns the result of `fs.readFileSync(path.join(fixtures.fixturesDir, ...args), 'enc')`. ### fixtures.readKey(arg[, enc]) -* `arg` [<String>] +* `arg` [<string>] Returns the result of `fs.readFileSync(path.join(fixtures.fixturesDir, 'keys', arg), 'enc')`. +## Heap dump checker module + +This provides utilities for checking the validity of heap dumps. +This requires the usage of `--expose-internals`. + +### heap.recordState() + +Create a heap dump and an embedder graph copy for inspection. +The returned object has a `validateSnapshotNodes` function similar to the +one listed below. (`heap.validateSnapshotNodes(...)` is a shortcut for +`heap.recordState().validateSnapshotNodes(...)`.) + +### heap.validateSnapshotNodes(name, expected, options) + +* `name` [<string>] Look for this string as the name of heap dump nodes. +* `expected` [<Array>] A list of objects, possibly with an `children` + property that points to expected other adjacent nodes. +* `options` [<Array>] + * `loose` [<boolean>] Do not expect an exact listing of occurrences + of nodes with name `name` in `expected`. + +Create a heap dump and an embedder graph copy and validate occurrences. + + +```js +validateSnapshotNodes('TLSWRAP', [ + { + children: [ + { name: 'enc_out' }, + { name: 'enc_in' }, + { name: 'TLSWrap' } + ] + } +]); +``` + +## HTTP/2 Module + +The http2.js module provides a handful of utilities for creating mock HTTP/2 +frames for testing of HTTP/2 endpoints + + +```js +const http2 = require('../common/http2'); +``` + +### Class: Frame + +The `http2.Frame` is a base class that creates a `Buffer` containing a +serialized HTTP/2 frame header. + + +```js +// length is a 24-bit unsigned integer +// type is an 8-bit unsigned integer identifying the frame type +// flags is an 8-bit unsigned integer containing the flag bits +// id is the 32-bit stream identifier, if any. +const frame = new http2.Frame(length, type, flags, id); + +// Write the frame data to a socket +socket.write(frame.data); +``` + +The serialized `Buffer` may be retrieved using the `frame.data` property. + +### Class: DataFrame extends Frame + +The `http2.DataFrame` is a subclass of `http2.Frame` that serializes a `DATA` +frame. + + +```js +// id is the 32-bit stream identifier +// payload is a Buffer containing the DATA payload +// padlen is an 8-bit integer giving the number of padding bytes to include +// final is a boolean indicating whether the End-of-stream flag should be set, +// defaults to false. +const frame = new http2.DataFrame(id, payload, padlen, final); + +socket.write(frame.data); +``` + +### Class: HeadersFrame + +The `http2.HeadersFrame` is a subclass of `http2.Frame` that serializes a +`HEADERS` frame. + + +```js +// id is the 32-bit stream identifier +// payload is a Buffer containing the HEADERS payload (see either +// http2.kFakeRequestHeaders or http2.kFakeResponseHeaders). +// padlen is an 8-bit integer giving the number of padding bytes to include +// final is a boolean indicating whether the End-of-stream flag should be set, +// defaults to false. +const frame = new http2.HeadersFrame(id, payload, padlen, final); + +socket.write(frame.data); +``` + +### Class: SettingsFrame + +The `http2.SettingsFrame` is a subclass of `http2.Frame` that serializes an +empty `SETTINGS` frame. + + +```js +// ack is a boolean indicating whether or not to set the ACK flag. +const frame = new http2.SettingsFrame(ack); + +socket.write(frame.data); +``` + +### http2.kFakeRequestHeaders + +Set to a `Buffer` instance that contains a minimal set of serialized HTTP/2 +request headers to be used as the payload of a `http2.HeadersFrame`. + + +```js +const frame = new http2.HeadersFrame(1, http2.kFakeRequestHeaders, 0, true); + +socket.write(frame.data); +``` + +### http2.kFakeResponseHeaders + +Set to a `Buffer` instance that contains a minimal set of serialized HTTP/2 +response headers to be used as the payload a `http2.HeadersFrame`. + + +```js +const frame = new http2.HeadersFrame(1, http2.kFakeResponseHeaders, 0, true); + +socket.write(frame.data); +``` + +### http2.kClientMagic + +Set to a `Buffer` containing the preamble bytes an HTTP/2 client must send +upon initial establishment of a connection. + + +```js +socket.write(http2.kClientMagic); +``` + +## Internet Module + +The `common/internet` module provides utilities for working with +internet-related tests. + +### internet.addresses + +* [<Object>] + * `INET_HOST` [<string>] A generic host that has registered common + DNS records, supports both IPv4 and IPv6, and provides basic HTTP/HTTPS + services + * `INET4_HOST` [<string>] A host that provides IPv4 services + * `INET6_HOST` [<string>] A host that provides IPv6 services + * `INET4_IP` [<string>] An accessible IPv4 IP, defaults to the + Google Public DNS IPv4 address + * `INET6_IP` [<string>] An accessible IPv6 IP, defaults to the + Google Public DNS IPv6 address + * `INVALID_HOST` [<string>] An invalid host that cannot be resolved + * `MX_HOST` [<string>] A host with MX records registered + * `SRV_HOST` [<string>] A host with SRV records registered + * `PTR_HOST` [<string>] A host with PTR records registered + * `NAPTR_HOST` [<string>] A host with NAPTR records registered + * `SOA_HOST` [<string>] A host with SOA records registered + * `CNAME_HOST` [<string>] A host with CNAME records registered + * `NS_HOST` [<string>] A host with NS records registered + * `TXT_HOST` [<string>] A host with TXT records registered + * `DNS4_SERVER` [<string>] An accessible IPv4 DNS server + * `DNS6_SERVER` [<string>] An accessible IPv6 DNS server + +A set of addresses for internet-related tests. All properties are configurable +via `NODE_TEST_*` environment variables. For example, to configure +`internet.addresses.INET_HOST`, set the environment +variable `NODE_TEST_INET_HOST` to a specified host. + +## tmpdir Module + +The `tmpdir` module supports the use of a temporary directory for testing. + +### path +* [<string>] + +The realpath of the testing temporary directory. + +### refresh() + +Deletes and recreates the testing temporary directory. + ## WPT Module The wpt.js module is a port of parts of @@ -517,15 +762,16 @@ Node.js implementation with tests from [W3C Web Platform Tests](https://github.com/w3c/web-platform-tests). + [<Array>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array [<ArrayBufferView[]>]: https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView -[<Boolean>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type [<Buffer>]: https://nodejs.org/api/buffer.html#buffer_class_buffer [<Function>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function -[<Number>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type [<Object>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object [<RegExp>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp -[<String>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type +[<boolean>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type +[<number>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type +[<string>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type [`common.hijackStdErr()`]: #hijackstderrlistener [`common.hijackStdOut()`]: #hijackstdoutlistener [internationalization]: https://github.com/nodejs/node/wiki/Intl diff --git a/test/common/benchmark.js b/test/common/benchmark.js index 555dc620f4..56ee8e5719 100644 --- a/test/common/benchmark.js +++ b/test/common/benchmark.js @@ -1,21 +1,11 @@ +'use strict'; + /**/ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ 'use strict'; @@ -46,10 +36,24 @@ function runBenchmark(name, args, env) { var mergedEnv = Object.assign({}, process.env, env); - var child = fork(runjs, argv, { env: mergedEnv }); + var child = fork(runjs, argv, { env: mergedEnv, stdio: 'pipe' }); + child.stdout.setEncoding('utf8'); + + var stdout = ''; + child.stdout.on('data', function (line) { + stdout += line; + }); + child.on('exit', function (code, signal) { assert.strictEqual(code, 0); assert.strictEqual(signal, null); + // This bit makes sure that each benchmark file is being sent settings such + // that the benchmark file runs just one set of options. This helps keep the + // benchmark tests from taking a long time to run. Therefore, each benchmark + // file should result in three lines of output: a blank line, a line with + // the name of the benchmark file, and a line with the only results that we + // get from testing the benchmark file. + assert.ok(/^(?:\n.+?\n.+?\n)+$/.test(stdout), 'benchmark file not running exactly one configuration in test: ' + stdout); }); } diff --git a/test/common/countdown.js b/test/common/countdown.js index 411fb69d2e..f09c35be1e 100644 --- a/test/common/countdown.js +++ b/test/common/countdown.js @@ -1,3 +1,5 @@ +'use strict'; + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -7,19 +9,8 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ + 'use strict'; /**/ @@ -34,6 +25,7 @@ var objectKeys = objectKeys || function (obj) { var assert = require('assert'); var kLimit = Symbol('limit'); var kCallback = Symbol('callback'); +var common = require('./'); var Countdown = function () { function Countdown(limit, cb) { @@ -42,7 +34,7 @@ var Countdown = function () { assert.strictEqual(typeof limit, 'number'); assert.strictEqual(typeof cb, 'function'); this[kLimit] = limit; - this[kCallback] = cb; + this[kCallback] = common.mustCall(cb); } Countdown.prototype.dec = function dec() { diff --git a/test/common/dns.js b/test/common/dns.js index 388c8df83d..25aa816a6c 100644 --- a/test/common/dns.js +++ b/test/common/dns.js @@ -1,3 +1,5 @@ +'use strict'; + var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**/ @@ -5,19 +7,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ 'use strict'; /**/ @@ -29,8 +19,6 @@ var objectKeys = objectKeys || function (obj) { }; /**/ -// Naïve DNS parser/serializer. - var assert = require('assert'); var os = require('os'); @@ -50,6 +38,8 @@ var classes = { IN: 1 }; +// Naïve DNS parser/serializer. + function readDomainFromPacket(buffer, offset) { assert.ok(offset < buffer.length); var length = buffer[offset]; @@ -409,7 +399,32 @@ function writeDNSPacket(parsed) { })); } -module.exports = { types: types, classes: classes, writeDNSPacket: writeDNSPacket, parseDNSPacket: parseDNSPacket }; +var mockedErrorCode = 'ENOTFOUND'; +var mockedSysCall = 'getaddrinfo'; + +function errorLookupMock() { + var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : mockedErrorCode; + var syscall = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : mockedSysCall; + + return function lookupWithError(host, dnsopts, cb) { + var err = new Error(syscall + ' ' + code + ' ' + host); + err.code = code; + err.errno = code; + err.syscall = syscall; + err.hostname = host; + cb(err); + }; +} + +module.exports = { + types: types, + classes: classes, + writeDNSPacket: writeDNSPacket, + parseDNSPacket: parseDNSPacket, + errorLookupMock: errorLookupMock, + mockedErrorCode: mockedErrorCode, + mockedSysCall: mockedSysCall +}; function forEach(xs, f) { for (var i = 0, l = xs.length; i < l; i++) { diff --git a/test/common/duplexpair.js b/test/common/duplexpair.js index b4b9577e9c..bcd219274d 100644 --- a/test/common/duplexpair.js +++ b/test/common/duplexpair.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -9,19 +11,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ 'use strict'; /**/ diff --git a/test/common/fixtures.js b/test/common/fixtures.js index 75f170d8c1..390bf20ba3 100644 --- a/test/common/fixtures.js +++ b/test/common/fixtures.js @@ -1,3 +1,5 @@ +'use strict'; + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /**/ @@ -5,19 +7,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ 'use strict'; /**/ diff --git a/test/common/heap.js b/test/common/heap.js new file mode 100644 index 0000000000..5d7c8f4be1 --- /dev/null +++ b/test/common/heap.js @@ -0,0 +1,206 @@ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/ /* eslint-disable node-core/required-modules */ +'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +var assert = require('assert'); + +/**/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/**/ + +var internalTestHeap = void 0; +try { + internalTestHeap = require('internal/test/heap'); +} catch (e) { + console.log('using `test/common/heap.js` requires `--expose-internals`'); + throw e; +} +var _internalTestHeap = internalTestHeap, + createJSHeapDump = _internalTestHeap.createJSHeapDump, + buildEmbedderGraph = _internalTestHeap.buildEmbedderGraph; + +var State = function () { + function State() { + _classCallCheck(this, State); + + this.snapshot = createJSHeapDump(); + this.embedderGraph = buildEmbedderGraph(); + } + + State.prototype.validateSnapshotNodes = function validateSnapshotNodes(name, expected) { + var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + _ref$loose = _ref.loose, + loose = _ref$loose === undefined ? false : _ref$loose; + + var snapshot = this.snapshot.filter(function (node) { + return node.name === 'Node / ' + name && node.type !== 'string'; + }); + if (loose) assert(snapshot.length >= expected.length);else assert.strictEqual(snapshot.length, expected.length); + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = expected[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var expectedNode = _step.value; + + if (expectedNode.children) { + var _loop = function (expectedChild) { + var check = typeof expectedChild === 'function' ? expectedChild : function (node) { + return [expectedChild.name, 'Node / ' + expectedChild.name].includes(node.name); + }; + + assert(snapshot.some(function (node) { + return node.outgoingEdges.map(function (edge) { + return edge.toNode; + }).some(check); + }), 'expected to find child ' + util.inspect(expectedChild) + ' ' + ('in ' + util.inspect(snapshot))); + }; + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = expectedNode.children[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var expectedChild = _step3.value; + + _loop(expectedChild); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + var graph = this.embedderGraph.filter(function (node) { + return node.name === name; + }); + if (loose) assert(graph.length >= expected.length);else assert.strictEqual(graph.length, expected.length); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = expected[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var _expectedNode = _step2.value; + + if (_expectedNode.edges) { + var _loop2 = function (_expectedChild) { + var check = typeof _expectedChild === 'function' ? _expectedChild : function (node) { + return node.name === _expectedChild.name || node.value && node.value.constructor && node.value.constructor.name === _expectedChild.name; + }; + + assert(graph.some(function (node) { + return node.edges.some(check); + }), 'expected to find child ' + util.inspect(_expectedChild) + ' ' + ('in ' + util.inspect(snapshot))); + }; + + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = _expectedNode.children[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + var _expectedChild = _step4.value; + + _loop2(_expectedChild); + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + }; + + return State; +}(); + +function recordState() { + return new State(); +} + +function validateSnapshotNodes() { + var _recordState; + + return (_recordState = recordState()).validateSnapshotNodes.apply(_recordState, arguments); +} + +module.exports = { + recordState: recordState, + validateSnapshotNodes: validateSnapshotNodes +}; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/http2.js b/test/common/http2.js new file mode 100644 index 0000000000..1327800fdf --- /dev/null +++ b/test/common/http2.js @@ -0,0 +1,227 @@ +'use strict'; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/ /* eslint-disable node-core/required-modules */ +'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +// An HTTP/2 testing tool used to create mock frames for direct testing +// of HTTP/2 endpoints. + +var kFrameData = Symbol('frame-data'); +var FLAG_EOS = 0x1; +var FLAG_ACK = 0x1; +var FLAG_EOH = 0x4; +var FLAG_PADDED = 0x8; +var PADDING = Buffer.alloc(255); + +var kClientMagic = Buffer.from('505249202a20485454502f322' + 'e300d0a0d0a534d0d0a0d0a', 'hex'); + +var kFakeRequestHeaders = Buffer.from('828684410f7777772e65' + '78616d706c652e636f6d', 'hex'); + +var kFakeResponseHeaders = Buffer.from('4803333032580770726976617465611d' + '4d6f6e2c203231204f63742032303133' + '2032303a31333a323120474d546e1768' + '747470733a2f2f7777772e6578616d70' + '6c652e636f6d', 'hex'); + +function isUint32(val) { + return val >>> 0 === val; +} + +function isUint24(val) { + return val >>> 0 === val && val <= 0xFFFFFF; +} + +function isUint8(val) { + return val >>> 0 === val && val <= 0xFF; +} + +function write32BE(array, pos, val) { + if (!isUint32(val)) throw new RangeError('val is not a 32-bit number'); + array[pos++] = val >> 24 & 0xff; + array[pos++] = val >> 16 & 0xff; + array[pos++] = val >> 8 & 0xff; + array[pos++] = val & 0xff; +} + +function write24BE(array, pos, val) { + if (!isUint24(val)) throw new RangeError('val is not a 24-bit number'); + array[pos++] = val >> 16 & 0xff; + array[pos++] = val >> 8 & 0xff; + array[pos++] = val & 0xff; +} + +function write8(array, pos, val) { + if (!isUint8(val)) throw new RangeError('val is not an 8-bit number'); + array[pos] = val; +} + +var Frame = function () { + function Frame(length, type, flags, id) { + _classCallCheck(this, Frame); + + this[kFrameData] = Buffer.alloc(9); + write24BE(this[kFrameData], 0, length); + write8(this[kFrameData], 3, type); + write8(this[kFrameData], 4, flags); + write32BE(this[kFrameData], 5, id); + } + + _createClass(Frame, [{ + key: 'data', + get: function () { + return this[kFrameData]; + } + }]); + + return Frame; +}(); + +var SettingsFrame = function (_Frame) { + _inherits(SettingsFrame, _Frame); + + function SettingsFrame() { + var ack = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + _classCallCheck(this, SettingsFrame); + + var flags = 0; + if (ack) flags |= FLAG_ACK; + return _possibleConstructorReturn(this, _Frame.call(this, 0, 4, flags, 0)); + } + + return SettingsFrame; +}(Frame); + +var DataFrame = function (_Frame2) { + _inherits(DataFrame, _Frame2); + + function DataFrame(id, payload) { + var padlen = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var final = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + _classCallCheck(this, DataFrame); + + var len = payload.length; + var flags = 0; + if (final) flags |= FLAG_EOS; + var buffers = [payload]; + if (padlen > 0) { + buffers.unshift(Buffer.from([padlen])); + buffers.push(PADDING.slice(0, padlen)); + len += padlen + 1; + flags |= FLAG_PADDED; + } + + var _this2 = _possibleConstructorReturn(this, _Frame2.call(this, len, 0, flags, id)); + + buffers.unshift(_this2[kFrameData]); + _this2[kFrameData] = Buffer.concat(buffers); + return _this2; + } + + return DataFrame; +}(Frame); + +var HeadersFrame = function (_Frame3) { + _inherits(HeadersFrame, _Frame3); + + function HeadersFrame(id, payload) { + var padlen = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var final = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + _classCallCheck(this, HeadersFrame); + + var len = payload.length; + var flags = FLAG_EOH; + if (final) flags |= FLAG_EOS; + var buffers = [payload]; + if (padlen > 0) { + buffers.unshift(Buffer.from([padlen])); + buffers.push(PADDING.slice(0, padlen)); + len += padlen + 1; + flags |= FLAG_PADDED; + } + + var _this3 = _possibleConstructorReturn(this, _Frame3.call(this, len, 1, flags, id)); + + buffers.unshift(_this3[kFrameData]); + _this3[kFrameData] = Buffer.concat(buffers); + return _this3; + } + + return HeadersFrame; +}(Frame); + +var PingFrame = function (_Frame4) { + _inherits(PingFrame, _Frame4); + + function PingFrame() { + var ack = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + _classCallCheck(this, PingFrame); + + var buffers = [Buffer.alloc(8)]; + + var _this4 = _possibleConstructorReturn(this, _Frame4.call(this, 8, 6, ack ? 1 : 0, 0)); + + buffers.unshift(_this4[kFrameData]); + _this4[kFrameData] = Buffer.concat(buffers); + return _this4; + } + + return PingFrame; +}(Frame); + +var AltSvcFrame = function (_Frame5) { + _inherits(AltSvcFrame, _Frame5); + + function AltSvcFrame(size) { + _classCallCheck(this, AltSvcFrame); + + var buffers = [Buffer.alloc(size)]; + + var _this5 = _possibleConstructorReturn(this, _Frame5.call(this, size, 10, 0, 0)); + + buffers.unshift(_this5[kFrameData]); + _this5[kFrameData] = Buffer.concat(buffers); + return _this5; + } + + return AltSvcFrame; +}(Frame); + +module.exports = { + Frame: Frame, + AltSvcFrame: AltSvcFrame, + DataFrame: DataFrame, + HeadersFrame: HeadersFrame, + SettingsFrame: SettingsFrame, + PingFrame: PingFrame, + kFakeRequestHeaders: kFakeRequestHeaders, + kFakeResponseHeaders: kFakeResponseHeaders, + kClientMagic: kClientMagic +}; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/index.js b/test/common/index.js index 33fa11e8d6..67d596414c 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -1,3 +1,7 @@ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } @@ -7,19 +11,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -// Copyright Joyent, Inc. and other Node contributors. +} /**/ // 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 @@ -40,7 +32,7 @@ if (!global.clearImmediate) { // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -/* eslint-disable required-modules, crypto-check */ +/* eslint-disable node-core/required-modules, node-core/crypto-check */ 'use strict'; /**/ @@ -52,6 +44,7 @@ var objectKeys = objectKeys || function (obj) { }; /**/ +var process = global.process; // Some tests tamper with the process global. var path = require('path'); var fs = require('fs'); var assert = require('assert'); @@ -72,64 +65,89 @@ util.inherits = require('inherits'); var Timer = { now: function () {} }; +var _process$binding = process.binding('config'), + hasTracing = _process$binding.hasTracing; + var _require2 = require('./fixtures'), fixturesDir = _require2.fixturesDir; -var testRoot = process.env.NODE_TEST_DIR ? fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..'); +var tmpdir = require('./tmpdir'); var noop = function () {}; -// Using a `.` prefixed name, which is the convention for "hidden" on POSIX, -// gets tools to ignore it by default or by simple rules, especially eslint. -var tmpDirName = '.tmp'; -// PORT should match the definition in test/testpy/__init__.py. -exports.PORT = +process.env.NODE_COMMON_PORT || 12346; +/**/if (!process.browser) { + Object.defineProperty(exports, 'PORT', { + get: function () { + if (+process.env.TEST_PARALLEL) { + throw new Error('common.PORT cannot be used in a parallelized test'); + } + return +process.env.NODE_COMMON_PORT || 12346; + }, + enumerable: true + }); +} /**/ + +exports.isMainThread = function () { + try { + return require('worker_threads').isMainThread; + } catch (_e) { + // Worker module not enabled → only a single main thread exists. + return true; + } +}(); + 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.isOpenBSD = process.platform === 'openbsd'; exports.isLinux = process.platform === 'linux'; exports.isOSX = process.platform === 'darwin'; +var isGlibc = void 0; +exports.isGlibc = function () { + if (isGlibc !== undefined) return isGlibc; + try { + var lddOut = spawnSync('ldd', [process.execPath]).stdout; + var libcInfo = lddOut.toString().split('\n').map(function (line) { + return line.match(/libc\.so.+=>\s*(\S+)\s/); + }).filter(function (info) { + return info; + }); + if (libcInfo.length === 0) return isGlibc = false; + var nmOut = spawnSync('nm', ['-D', libcInfo[0][1]]).stdout; + if (/gnu_get_libc_version/.test(nmOut)) return isGlibc = true; + } catch (_e) {} + return isGlibc = false; +}; + exports.enoughTestMem = os.totalmem() > 0x70000000; /* 1.75 Gb */ var cpus = os.cpus(); /*exports.enoughTestCpu = Array.isArray(cpus) && (cpus.length > 1 || cpus[0].speed > 999);*/ exports.rootDir = exports.isWindows ? 'c:\\' : '/'; -exports.projectDir = path.resolve(__dirname, '..', '..'); //exports.buildType = process.config.target_defaults.default_configuration; -// Always enable async_hooks checks in tests -{ - // const async_wrap = process.binding('async_wrap'); - // const kCheck = async_wrap.constants.kCheck; - // async_wrap.async_hook_fields[kCheck] += 1; - - exports.revert_force_async_hooks_checks = function () { - async_wrap.async_hook_fields[kCheck] -= 1; - }; -} - // If env var is set then enable async_hook hooks for all tests. if (process.env.NODE_TEST_WITH_ASYNC_HOOKS) { var destroydIdsList = {}; var destroyListList = {}; var initHandles = {}; - var _async_wrap = process.binding('async_wrap'); + var async_wrap = process.binding('async_wrap'); process.on('exit', function () { - // itterate through handles to make sure nothing crashes + // iterate through handles to make sure nothing crashes for (var k in initHandles) { util.inspect(initHandles[k]); } }); - var _queueDestroyAsyncId = _async_wrap.queueDestroyAsyncId; - _async_wrap.queueDestroyAsyncId = function queueDestroyAsyncId(id) { + var _queueDestroyAsyncId = async_wrap.queueDestroyAsyncId; + async_wrap.queueDestroyAsyncId = function queueDestroyAsyncId(id) { if (destroyListList[id] !== undefined) { process._rawDebug(destroyListList[id]); process._rawDebug(); @@ -162,55 +180,6 @@ if (process.env.NODE_TEST_WITH_ASYNC_HOOKS) { }).enable();*/ } -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'; - forEach(fs.readdirSync(p, enc), 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; - tmpDirName += '.' + process.env.TEST_THREAD_ID; -} -exports.tmpDir = path.join(testRoot, tmpDirName); - var opensslCli = null; var inFreeBSDJail = null; var localhostIPv4 = null; @@ -298,6 +267,14 @@ if (exports.isLinux) { }); } /**/ +/**/if (!process.browser) { + Object.defineProperty(exports, 'hasTracing', { + get: function () { + return Boolean(hasTracing); + } + }); +} /**/ + /**/if (!process.browser) { Object.defineProperty(exports, 'hasFipsCrypto', { get: function () { @@ -307,7 +284,7 @@ if (exports.isLinux) { } /**/ { - var localRelative = path.relative(process.cwd(), exports.tmpDir + '/'); + var localRelative = path.relative(process.cwd(), tmpdir.path + '/'); var pipePrefix = exports.isWindows ? '\\\\.\\pipe\\' : localRelative; var pipeName = 'node-test.' + process.pid + '.sock'; exports.PIPE = path.join(pipePrefix, pipeName); @@ -387,8 +364,7 @@ exports.platformTimeout = function (ms) { return ms; // ARMv8+ }; -var knownGlobals = [Buffer, clearImmediate, clearInterval, clearTimeout, console, constructor, // Enumerable in V8 3.21. -global, process, setImmediate, setInterval, setTimeout]; +var knownGlobals = [Buffer, clearImmediate, clearInterval, clearTimeout, global, process, setImmediate, setInterval, setTimeout]; if (global.gc) { knownGlobals.push(global.gc); @@ -412,40 +388,6 @@ if (global.COUNTER_NET_SERVER_CONNECTION) { 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 (!process.browser) { - 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); -} - if (process.env.NODE_TEST_KNOWN_GLOBALS) { var knownFromEnv = process.env.NODE_TEST_KNOWN_GLOBALS.split(','); allowGlobals.apply(undefined, _toConsumableArray(knownFromEnv)); @@ -465,7 +407,7 @@ 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) { +'console,clearImmediate,setImmediate,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]); @@ -490,11 +432,7 @@ function leakedGlobals() { } exports.leakedGlobals = leakedGlobals; -// Turn this off if the test should not check for global leaks. -exports.globalCheck = true; - process.on('exit', function () { - if (!exports.globalCheck) return; var leaked = leakedGlobals(); if (leaked.length > 0) { assert.fail('Unexpected global(s) found: ' + leaked.join(', ')); @@ -532,6 +470,14 @@ exports.mustCallAtLeast = function (fn, minimum) { return _mustCallInner(fn, minimum, 'minimum'); }; +exports.mustCallAsync = function (fn, exact) { + return exports.mustCall(function () { + return Promise.resolve(fn.apply(undefined, arguments)).then(exports.mustCall(function (val) { + return val; + })); + }, exact); +}; + function _mustCallInner(fn) { var _context; @@ -562,9 +508,9 @@ function _mustCallInner(fn) { } exports.hasMultiLocalhost = function hasMultiLocalhost() { - var _process$binding = process.binding('tcp_wrap'), - TCP = _process$binding.TCP, - TCPConstants = _process$binding.constants; + var _process$binding2 = process.binding('tcp_wrap'), + TCP = _process$binding2.TCP, + TCPConstants = _process$binding2.constants; var t = new TCP(TCPConstants.SOCKET); var ret = t.bind('127.0.0.2', 0); @@ -582,7 +528,7 @@ exports.fileExists = function (pathname) { }; exports.skipIfEslintMissing = function () { - if (!exports.fileExists(path.join('..', '..', 'tools', 'node_modules', 'eslint'))) { + if (!exports.fileExists(path.join(__dirname, '..', '..', 'tools', 'node_modules', 'eslint'))) { exports.skip('missing ESLint'); } }; @@ -595,22 +541,16 @@ exports.canCreateSymLink = function () { // 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 = ''; + var whoamiPath = path.join(process.env.SystemRoot, 'System32', 'whoami.exe'); try { - output = execSync(whoamiPath + ' /priv', { timout: 1000 }); + var output = execSync(whoamiPath + ' /priv', { timout: 1000 }); + return output.includes('SeCreateSymbolicLinkPrivilege'); } catch (e) { - err = true; - } finally { - if (err || !output.includes('SeCreateSymbolicLinkPrivilege')) { - return false; - } + return false; } } - + // On non-Windows platforms, this always returns `true` return true; }; @@ -680,9 +620,9 @@ exports.nodeProcessAborted = function nodeProcessAborted(exitCode, signal) { // On Windows, 'aborts' are of 2 types, depending on the context: // (i) Forced access violation, if --abort-on-uncaught-exception is on // which corresponds to exit code 3221225477 (0xC0000005) - // (ii) raise(SIGABRT) or abort(), which lands up in CRT library calls - // which corresponds to exit code 3. - if (exports.isWindows) expectedExitCodes = [3221225477, 3]; + // (ii) Otherwise, _exit(134) which is called in place of abort() due to + // raising SIGABRT exiting with ambiguous exit code '3' by default + if (exports.isWindows) expectedExitCodes = [0xC0000005, 134]; // When using --abort-on-uncaught-exception, V8 will use // base::OS::Abort to terminate the process. @@ -713,19 +653,24 @@ exports.isAlive = function isAlive(pid) { } }; -function expectWarning(name, expectedMessages) { +exports.noWarnCode = undefined; + +function expectWarning(name, expected) { + var map = new Map(expected); return exports.mustCall(function (warning) { assert.strictEqual(warning.name, name); - assert.ok(expectedMessages.includes(warning.message), 'unexpected error message: "' + warning.message + '"'); + assert.ok(map.has(warning.message), 'unexpected error message: "' + warning.message + '"'); + var code = map.get(warning.message); + assert.strictEqual(warning.code, code); // Remove a warning message after it is seen so that we guarantee that we // get each message only once. - expectedMessages.splice(expectedMessages.indexOf(warning.message), 1); - }, expectedMessages.length); + map.delete(expected); + }, expected.length); } -function expectWarningByName(name, expected) { +function expectWarningByName(name, expected, code) { if (typeof expected === 'string') { - expected = [expected]; + expected = [[expected, code]]; } process.on('warning', expectWarning(name, expected)); } @@ -734,8 +679,14 @@ function expectWarningByMap(warningMap) { var catchWarning = {}; forEach(objectKeys(warningMap), function (name) { var expected = warningMap[name]; - if (typeof expected === 'string') { - expected = [expected]; + if (!Array.isArray(expected)) { + throw new Error('warningMap entries must be arrays consisting of two ' + 'entries: [message, warningCode]'); + } + if (!Array.isArray(expected[0])) { + if (expected.length === 0) { + return; + } + expected = [[expected[0], expected[1]]]; } catchWarning[name] = expectWarning(name, expected); }); @@ -747,9 +698,9 @@ function expectWarningByMap(warningMap) { // 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) { +exports.expectWarning = function (nameOrMap, expected, code) { if (typeof nameOrMap === 'string') { - expectWarningByName(nameOrMap, expected); + expectWarningByName(nameOrMap, expected, code); } else { expectWarningByMap(nameOrMap); } @@ -771,42 +722,123 @@ exports.expectWarning = function (nameOrMap, expected) { }); } /**/ +var Comparison = function Comparison(obj, keys) { + _classCallCheck(this, Comparison); + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var key = _step.value; + + if (key in obj) this[key] = obj[key]; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } +}; + // Useful for testing expected internal/error objects + + exports.expectsError = function expectsError(fn, settings, exact) { if (typeof fn !== 'function') { exact = settings; settings = fn; fn = undefined; } + function innerFn(error) { - assert.strictEqual(error.code, settings.code); + if (arguments.length !== 1) { + // Do not use `assert.strictEqual()` to prevent `util.inspect` from + // always being called. + assert.fail('Expected one argument, got ' + util.inspect(arguments)); + } + var descriptor = Object.getOwnPropertyDescriptor(error, 'message'); + assert.strictEqual(descriptor.enumerable, false, 'The error message should be non-enumerable'); + + var innerSettings = settings; if ('type' in settings) { var type = settings.type; if (type !== Error && !Error.isPrototypeOf(type)) { throw new TypeError('`settings.type` must inherit from `Error`'); } - assert(error instanceof type, error.name + ' is not instance of ' + type.name); - } - if ('message' in settings) { - var message = settings.message; - if (typeof message === 'string') { - assert.strictEqual(error.message, message); - } else { - assert(message.test(error.message), error.message + ' does not match ' + message); + var _constructor = error.constructor; + if (_constructor.name === 'NodeError' && type.name !== 'NodeError') { + _constructor = Object.getPrototypeOf(error.constructor); } + // Add the `type` to the error to properly compare and visualize it. + if (!('type' in error)) error.type = _constructor; } - if ('name' in settings) { - assert.strictEqual(error.name, settings.name); + + if ('message' in settings && typeof settings.message === 'object' && settings.message.test(error.message)) { + // Make a copy so we are able to modify the settings. + innerSettings = Object.create(settings, Object.getOwnPropertyDescriptors(settings)); + // Visualize the message as identical in case of other errors. + innerSettings.message = error.message; } - if (error.constructor.name === 'AssertionError') { - forEach(['generatedMessage', 'actual', 'expected', 'operator'], function (key) { - if (key in settings) { - var actual = error[key]; - var expected = settings[key]; - assert.strictEqual(actual, expected, key + ': expected ' + expected + ', not ' + actual); + + // Check all error properties. + var keys = objectKeys(settings); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var key = _step2.value; + + if (!require('deep-strict-equal')(error[key], innerSettings[key])) { + // Create placeholder objects to create a nice output. + var a = new Comparison(error, keys); + var b = new Comparison(innerSettings, keys); + + var tmpLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + var err = new assert.AssertionError({ + actual: a, + expected: b, + operator: 'strictEqual', + stackStartFn: assert.throws + }); + Error.stackTraceLimit = tmpLimit; + + throw new assert.AssertionError({ + actual: error, + expected: settings, + operator: 'common.expectsError', + message: err.message + }); } - }); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } } + return true; } if (fn) { @@ -820,6 +852,10 @@ exports.skipIfInspectorDisabled = function skipIfInspectorDisabled() { if (process.config.variables.v8_enable_inspector === 0) { exports.skip('V8 inspector is disabled'); } + if (!exports.isMainThread) { + // TODO(addaleax): Fix me. + exports.skip('V8 inspector is not available in Workers'); + } }; exports.skipIf32Bits = function skipIf32Bits() { @@ -838,13 +874,13 @@ exports.getArrayBufferViews = function getArrayBufferViews(buf) { var arrayBufferViews = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, DataView]; - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; try { - for (var _iterator = arrayBufferViews[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var type = _step.value; + for (var _iterator3 = arrayBufferViews[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var type = _step3.value; var _type$BYTES_PER_ELEME = type.BYTES_PER_ELEMENT, BYTES_PER_ELEMENT = _type$BYTES_PER_ELEME === undefined ? 1 : _type$BYTES_PER_ELEME; @@ -853,16 +889,16 @@ exports.getArrayBufferViews = function getArrayBufferViews(buf) { } } } catch (err) { - _didIteratorError = true; - _iteratorError = err; + _didIteratorError3 = true; + _iteratorError3 = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); } } finally { - if (_didIteratorError) { - throw _iteratorError; + if (_didIteratorError3) { + throw _iteratorError3; } } } @@ -870,27 +906,34 @@ exports.getArrayBufferViews = function getArrayBufferViews(buf) { return out; }; +exports.getBufferSources = function getBufferSources(buf) { + return [].concat(_toConsumableArray(exports.getArrayBufferViews(buf)), [new Uint8Array(buf).buffer]); +}; + // Crash the process on unhandled rejections. -exports.crashOnUnhandledRejection = function () { - process.on('unhandledRejection', function (err) { - return process.nextTick(function () { - throw err; - }); - }); +var crashOnUnhandledRejection = function (err) { + throw err; +}; +process.on('unhandledRejection', crashOnUnhandledRejection); +exports.disableCrashOnUnhandledRejection = function () { + process.removeListener('unhandledRejection', crashOnUnhandledRejection); }; exports.getTTYfd = function getTTYfd() { + // Do our best to grab a tty fd. var tty = require('tty'); - var tty_fd = 0; - if (!tty.isatty(tty_fd)) tty_fd++;else if (!tty.isatty(tty_fd)) tty_fd++;else if (!tty.isatty(tty_fd)) tty_fd++;else { + // Don't attempt fd 0 as it is not writable on Windows. + // Ref: ef2861961c3d9e9ed6972e1e84d969683b25cf95 + var ttyFd = [1, 2, 4, 5].find(tty.isatty); + if (ttyFd === undefined) { try { - tty_fd = fs.openSync('/dev/tty'); + return fs.openSync('/dev/tty'); } catch (e) { // There aren't any tty fd's available to use. return -1; } } - return tty_fd; + return ttyFd; }; // Hijack stdout and stderr @@ -919,18 +962,50 @@ function restoreWritable(name) { delete process[name].writeTimes; } +exports.runWithInvalidFD = function (func) { + var fd = 1 << 30; + // Get first known bad file descriptor. 1 << 30 is usually unlikely to + // be an valid one. + try { + while (fs.fstatSync(fd--) && fd > 0) {} + } catch (e) { + return func(fd); + } + + exports.printSkipMessage('Could not generate an invalid fd'); +}; + exports.hijackStdout = hijackStdWritable.bind(null, 'stdout'); exports.hijackStderr = hijackStdWritable.bind(null, 'stderr'); exports.restoreStdout = restoreWritable.bind(null, 'stdout'); exports.restoreStderr = restoreWritable.bind(null, 'stderr'); +exports.isCPPSymbolsNotMapped = exports.isWindows || exports.isSunOS || exports.isAIX || exports.isLinuxPPCBE || exports.isFreeBSD; -var fd = 2; -exports.firstInvalidFD = function firstInvalidFD() { - // Get first known bad file descriptor. - try { - while (fs.fstatSync(++fd)) {} - } catch (e) {} - return fd; +var gcTrackerMap = new WeakMap(); +var gcTrackerTag = 'NODE_TEST_COMMON_GC_TRACKER'; + +exports.onGC = function (obj, gcListener) { + var async_hooks = require('async_' + 'hooks'); + + var onGcAsyncHook = async_hooks.createHook({ + init: exports.mustCallAtLeast(function (id, type, trigger, resource) { + if (this.trackedId === undefined) { + assert.strictEqual(type, gcTrackerTag); + this.trackedId = id; + } + }), + destroy: function (id) { + assert.notStrictEqual(this.trackedId, -1); + if (id === this.trackedId) { + this.gcListener.ongc(); + onGcAsyncHook.disable(); + } + } + }).enable(); + onGcAsyncHook.gcListener = gcListener; + + gcTrackerMap.set(obj, new async_hooks.AsyncResource(gcTrackerTag)); + obj = null; }; function forEach(xs, f) { diff --git a/test/common/index.mjs b/test/common/index.mjs index ad89e9dc7d..d6e9f31fe3 100644 --- a/test/common/index.mjs +++ b/test/common/index.mjs @@ -2,127 +2,129 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) exports[i] = util[i]; - /**//**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -// Flags: --experimental-modules -/* eslint-disable required-modules */ - -import assert from 'assert'; - -let knownGlobals = [ - Buffer, - clearImmediate, - clearInterval, - clearTimeout, - console, - constructor, // Enumerable in V8 3.21. - global, - process, - setImmediate, - setInterval, - setTimeout -]; - -if (process.env.NODE_TEST_KNOWN_GLOBALS) { - const knownFromEnv = process.env.NODE_TEST_KNOWN_GLOBALS.split(','); - allowGlobals(...knownFromEnv); -} - -export function allowGlobals(...whitelist) { - knownGlobals = knownGlobals.concat(whitelist); -} - -export function leakedGlobals() { - //add possible expected globals - 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); - } - - const leaked = []; - - for (const val in global) { - if (!knownGlobals.includes(global[val])) { - leaked.push(val); - } - } - - if (global.__coverage__) { - return leaked.filter((varname) => !/^(?:cov_|__cov)/.test(varname)); - } else { - return leaked; - } -} - -// Turn this off if the test should not check for global leaks. -export let globalCheck = true; // eslint-disable-line - -process.on('exit', function() { - if (!globalCheck) return; - const leaked = leakedGlobals(); - if (leaked.length > 0) { - assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`); - } -}); + /**/// Flags: --experimental-modules +/* eslint-disable node-core/required-modules */ +import common from './index.js'; + +const { + PORT, + isMainThread, + isWindows, + isWOW64, + isAIX, + isLinuxPPCBE, + isSunOS, + isFreeBSD, + isOpenBSD, + isLinux, + isOSX, + isGlibc, + enoughTestMem, + enoughTestCpu, + rootDir, + buildType, + localIPv6Hosts, + opensslCli, + PIPE, + hasIPv6, + childShouldThrowAndAbort, + ddCommand, + spawnPwd, + spawnSyncPwd, + platformTimeout, + allowGlobals, + leakedGlobals, + mustCall, + mustCallAtLeast, + mustCallAsync, + hasMultiLocalhost, + fileExists, + skipIfEslintMissing, + canCreateSymLink, + getCallSite, + mustNotCall, + printSkipMessage, + skip, + ArrayStream, + nodeProcessAborted, + busyLoop, + isAlive, + noWarnCode, + expectWarning, + expectsError, + skipIfInspectorDisabled, + skipIf32Bits, + getArrayBufferViews, + getBufferSources, + disableCrashOnUnhandledRejection, + getTTYfd, + runWithInvalidFD, + hijackStdout, + hijackStderr, + restoreStdout, + restoreStderr, + isCPPSymbolsNotMapped +} = common; + +export { + PORT, + isMainThread, + isWindows, + isWOW64, + isAIX, + isLinuxPPCBE, + isSunOS, + isFreeBSD, + isOpenBSD, + isLinux, + isOSX, + isGlibc, + enoughTestMem, + enoughTestCpu, + rootDir, + buildType, + localIPv6Hosts, + opensslCli, + PIPE, + hasIPv6, + childShouldThrowAndAbort, + ddCommand, + spawnPwd, + spawnSyncPwd, + platformTimeout, + allowGlobals, + leakedGlobals, + mustCall, + mustCallAtLeast, + mustCallAsync, + hasMultiLocalhost, + fileExists, + skipIfEslintMissing, + canCreateSymLink, + getCallSite, + mustNotCall, + printSkipMessage, + skip, + ArrayStream, + nodeProcessAborted, + busyLoop, + isAlive, + noWarnCode, + expectWarning, + expectsError, + skipIfInspectorDisabled, + skipIf32Bits, + getArrayBufferViews, + getBufferSources, + disableCrashOnUnhandledRejection, + getTTYfd, + runWithInvalidFD, + hijackStdout, + hijackStderr, + restoreStdout, + restoreStderr, + isCPPSymbolsNotMapped +}; function forEach (xs, f) { for (var i = 0, l = xs.length; i < l; i++) { diff --git a/test/common/inspector-helper.js b/test/common/inspector-helper.js index 3e4f16573a..67cb54f6ce 100644 --- a/test/common/inspector-helper.js +++ b/test/common/inspector-helper.js @@ -1,3 +1,11 @@ +'use strict'; + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**/ @@ -5,19 +13,7 @@ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -'use strict'; +} /**/'use strict'; /**/ var objectKeys = objectKeys || function (obj) { @@ -37,7 +33,14 @@ var fixtures = require('../common/fixtures'); var _require = require('child_process'), spawn = _require.spawn; -var url = require('url'); +var _require2 = require('url'), + parseURL = _require2.parse; + +var _require3 = require('internal/url'), + getURLFromFilePath = _require3.getURLFromFilePath; + +var _require4 = require('events'), + EventEmitter = _require4.EventEmitter; var _MAINSCRIPT = fixtures.path('loop.js'); var DEBUG = false; @@ -55,6 +58,7 @@ function spawnChildProcess(inspectorFlags, scriptContents, scriptFile) { var handler = tearDown.bind(null, child); process.on('exit', handler); process.on('uncaughtException', handler); + common.disableCrashOnUnhandledRejection(); process.on('unhandledRejection', handler); process.on('SIGINT', handler); @@ -204,9 +208,18 @@ var InspectorSession = function () { return this._terminationPromise; }; - InspectorSession.prototype.disconnect = function disconnect() { - this._socket.destroy(); - }; + InspectorSession.prototype.disconnect = function () { + var _ref = _asyncToGenerator(function* () { + this._socket.destroy(); + return this.waitForServerDisconnect(); + }); + + function disconnect() { + return _ref.apply(this, arguments); + } + + return disconnect; + }(); InspectorSession.prototype._onMessage = function _onMessage(message) { if (message.id) { @@ -218,11 +231,15 @@ var InspectorSession = function () { if (message.result) resolve(message.result);else reject(message.error); } else { if (message.method === 'Debugger.scriptParsed') { - var script = message['params']; - var scriptId = script['scriptId']; - var _url = script['url']; - this._scriptsIdsByUrl.set(scriptId, _url); - if (_url === _MAINSCRIPT) this.mainScriptId = scriptId; + var _message$params = message.params, + scriptId = _message$params.scriptId, + url = _message$params.url; + + this._scriptsIdsByUrl.set(scriptId, url); + var fileUrl = url.startsWith('file:') ? url : getURLFromFilePath(url).toString(); + if (fileUrl === this.scriptURL().toString()) { + this.mainScriptId = scriptId; + } } if (this._notificationCallback) { @@ -240,11 +257,11 @@ var InspectorSession = function () { var _this2 = this; var msg = JSON.parse(JSON.stringify(message)); // Clone! - msg['id'] = this._nextId++; + msg.id = this._nextId++; if (DEBUG) console.log('[sent]', JSON.stringify(msg)); var responsePromise = new Promise(function (resolve, reject) { - _this2._commandResponsePromises.set(msg['id'], { resolve: resolve, reject: reject }); + _this2._commandResponsePromises.set(msg.id, { resolve: resolve, reject: reject }); }); return new Promise(function (resolve) { @@ -274,32 +291,41 @@ var InspectorSession = function () { return fires(this._asyncWaitForNotification(methodOrPredicate), message, TIMEOUT); }; - InspectorSession.prototype._asyncWaitForNotification = async function _asyncWaitForNotification(methodOrPredicate) { - var _this4 = this; + InspectorSession.prototype._asyncWaitForNotification = function () { + var _ref2 = _asyncToGenerator(function* (methodOrPredicate) { + var _this4 = this; - function matchMethod(notification) { - return notification.method === methodOrPredicate; - } - var predicate = typeof methodOrPredicate === 'string' ? matchMethod : methodOrPredicate; - var notification = null; - do { - if (this._unprocessedNotifications.length) { - notification = this._unprocessedNotifications.shift(); - } else { - notification = await new Promise(function (resolve) { - return _this4._notificationCallback = resolve; - }); + function matchMethod(notification) { + return notification.method === methodOrPredicate; } - } while (!predicate(notification)); - return notification; - }; + var predicate = typeof methodOrPredicate === 'string' ? matchMethod : methodOrPredicate; + var notification = null; + do { + if (this._unprocessedNotifications.length) { + notification = this._unprocessedNotifications.shift(); + } else { + notification = yield new Promise(function (resolve) { + return _this4._notificationCallback = resolve; + }); + } + } while (!predicate(notification)); + return notification; + }); + + function _asyncWaitForNotification(_x) { + return _ref2.apply(this, arguments); + } - InspectorSession.prototype._isBreakOnLineNotification = function _isBreakOnLineNotification(message, line, url) { - if ('Debugger.paused' === message['method']) { - var callFrame = message['params']['callFrames'][0]; - var location = callFrame['location']; - assert.strictEqual(url, this._scriptsIdsByUrl.get(location['scriptId'])); - assert.strictEqual(line, location['lineNumber']); + return _asyncWaitForNotification; + }(); + + InspectorSession.prototype._isBreakOnLineNotification = function _isBreakOnLineNotification(message, line, expectedScriptPath) { + if (message.method === 'Debugger.paused') { + var callFrame = message.params.callFrames[0]; + var location = callFrame.location; + var scriptPath = this._scriptsIdsByUrl.get(location.scriptId); + assert.strictEqual(scriptPath.toString(), expectedScriptPath.toString(), scriptPath + ' !== ' + expectedScriptPath); + assert.strictEqual(line, location.lineNumber); return true; } }; @@ -314,19 +340,19 @@ var InspectorSession = function () { InspectorSession.prototype._matchesConsoleOutputNotification = function _matchesConsoleOutputNotification(notification, type, values) { if (!Array.isArray(values)) values = [values]; - if ('Runtime.consoleAPICalled' === notification['method']) { - var params = notification['params']; - if (params['type'] === type) { + if (notification.method === 'Runtime.consoleAPICalled') { + var params = notification.params; + if (params.type === type) { var _i2 = 0; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { - for (var _iterator2 = params['args'][Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + for (var _iterator2 = params.args[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var value = _step2.value; - if (value['value'] !== values[_i2++]) return false; + if (value.value !== values[_i2++]) return false; } } catch (err) { _didIteratorError2 = true; @@ -357,62 +383,95 @@ var InspectorSession = function () { }, desc); }; - InspectorSession.prototype.runToCompletion = async function runToCompletion() { - console.log('[test]', 'Verify node waits for the frontend to disconnect'); - await this.send({ 'method': 'Debugger.resume' }); - await this.waitForNotification(function (notification) { - return notification.method === 'Runtime.executionContextDestroyed' && notification.params.executionContextId === 1; + InspectorSession.prototype.runToCompletion = function () { + var _ref3 = _asyncToGenerator(function* () { + console.log('[test]', 'Verify node waits for the frontend to disconnect'); + yield this.send({ 'method': 'Debugger.resume' }); + yield this.waitForNotification(function (notification) { + return notification.method === 'Runtime.executionContextDestroyed' && notification.params.executionContextId === 1; + }); + while ((yield this._instance.nextStderrString()) !== 'Waiting for the debugger to disconnect...') {} + yield this.disconnect(); }); - while ((await this._instance.nextStderrString()) !== 'Waiting for the debugger to disconnect...') {} - await this.disconnect(); + + function runToCompletion() { + return _ref3.apply(this, arguments); + } + + return runToCompletion; + }(); + + InspectorSession.prototype.scriptPath = function scriptPath() { + return this._instance.scriptPath(); + }; + + InspectorSession.prototype.script = function script() { + return this._instance.script(); + }; + + InspectorSession.prototype.scriptURL = function scriptURL() { + return getURLFromFilePath(this.scriptPath()); }; return InspectorSession; }(); -var NodeInstance = function () { +var NodeInstance = function (_EventEmitter) { + _inherits(NodeInstance, _EventEmitter); + function NodeInstance() { var inspectorFlags = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['--inspect-brk=0']; - - var _this7 = this; - var scriptContents = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; var scriptFile = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _MAINSCRIPT; _classCallCheck(this, NodeInstance); - this._portCallback = null; - this.portPromise = new Promise(function (resolve) { + var _this7 = _possibleConstructorReturn(this, _EventEmitter.call(this)); + + _this7._scriptPath = scriptFile; + _this7._script = scriptFile ? null : scriptContents; + _this7._portCallback = null; + _this7.portPromise = new Promise(function (resolve) { return _this7._portCallback = resolve; }); - this._process = spawnChildProcess(inspectorFlags, scriptContents, scriptFile); - this._running = true; - this._stderrLineCallback = null; - this._unprocessedStderrLines = []; - - this._process.stdout.on('data', makeBufferingDataCallback(function (line) { - return console.log('[out]', line); + _this7._process = spawnChildProcess(inspectorFlags, scriptContents, scriptFile); + _this7._running = true; + _this7._stderrLineCallback = null; + _this7._unprocessedStderrLines = []; + + _this7._process.stdout.on('data', makeBufferingDataCallback(function (line) { + _this7.emit('stdout', line); + console.log('[out]', line); })); - this._process.stderr.on('data', makeBufferingDataCallback(function (message) { + _this7._process.stderr.on('data', makeBufferingDataCallback(function (message) { return _this7.onStderrLine(message); })); - this._shutdownPromise = new Promise(function (resolve) { + _this7._shutdownPromise = new Promise(function (resolve) { _this7._process.once('exit', function (exitCode, signal) { resolve({ exitCode: exitCode, signal: signal }); _this7._running = false; }); }); + return _this7; } - NodeInstance.startViaSignal = async function startViaSignal(scriptContents) { - var instance = new NodeInstance([], scriptContents + '\nprocess._rawDebug(\'started\');', undefined); - var msg = 'Timed out waiting for process to start'; - while ((await fires(instance.nextStderrString(), msg, TIMEOUT)) !== 'started') {} - process._debugProcess(instance._process.pid); - return instance; - }; + NodeInstance.startViaSignal = function () { + var _ref4 = _asyncToGenerator(function* (scriptContents) { + var instance = new NodeInstance([], scriptContents + '\nprocess._rawDebug(\'started\');', undefined); + var msg = 'Timed out waiting for process to start'; + while ((yield fires(instance.nextStderrString(), msg, TIMEOUT)) !== 'started') {} + process._debugProcess(instance._process.pid); + return instance; + }); + + function startViaSignal(_x5) { + return _ref4.apply(this, arguments); + } + + return startViaSignal; + }(); NodeInstance.prototype.onStderrLine = function onStderrLine(line) { console.log('[err]', line); @@ -431,11 +490,12 @@ var NodeInstance = function () { } }; - NodeInstance.prototype.httpGet = function httpGet(host, path) { + NodeInstance.prototype.httpGet = function httpGet(host, path, hostHeaderValue) { console.log('[test]', 'Testing ' + path); + var headers = hostHeaderValue ? { 'Host': hostHeaderValue } : null; return this.portPromise.then(function (port) { return new Promise(function (resolve, reject) { - var req = http.get({ host: host, port: port, path: path }, function (res) { + var req = http.get({ host: host, port: port, path: path, headers: headers }, function (res) { var response = ''; res.setEncoding('utf8'); res.on('data', function (data) { @@ -456,33 +516,69 @@ var NodeInstance = function () { }); }; - NodeInstance.prototype.wsHandshake = function wsHandshake(devtoolsUrl) { - var _this8 = this; + NodeInstance.prototype.sendUpgradeRequest = function () { + var _ref5 = _asyncToGenerator(function* () { + var response = yield this.httpGet(null, '/json/list'); + var devtoolsUrl = response[0].webSocketDebuggerUrl; + var port = yield this.portPromise; + return http.get({ + port: port, + path: parseURL(devtoolsUrl).path, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Version': 13, + 'Sec-WebSocket-Key': 'key==' + } + }); + }); + + function sendUpgradeRequest() { + return _ref5.apply(this, arguments); + } - return this.portPromise.then(function (port) { - return new Promise(function (resolve) { - http.get({ - port: port, - path: url.parse(devtoolsUrl).path, - headers: { - 'Connection': 'Upgrade', - 'Upgrade': 'websocket', - 'Sec-WebSocket-Version': 13, - 'Sec-WebSocket-Key': 'key==' - } - }).on('upgrade', function (message, socket) { - resolve(new InspectorSession(socket, _this8)); + return sendUpgradeRequest; + }(); + + NodeInstance.prototype.connectInspectorSession = function () { + var _ref6 = _asyncToGenerator(function* () { + var _this8 = this; + + console.log('[test]', 'Connecting to a child Node process'); + var upgradeRequest = yield this.sendUpgradeRequest(); + return new Promise(function (resolve, reject) { + upgradeRequest.on('upgrade', function (message, socket) { + return resolve(new InspectorSession(socket, _this8)); }).on('response', common.mustNotCall('Upgrade was not received')); }); }); - }; - NodeInstance.prototype.connectInspectorSession = async function connectInspectorSession() { - console.log('[test]', 'Connecting to a child Node process'); - var response = await this.httpGet(null, '/json/list'); - var url = response[0]['webSocketDebuggerUrl']; - return this.wsHandshake(url); - }; + function connectInspectorSession() { + return _ref6.apply(this, arguments); + } + + return connectInspectorSession; + }(); + + NodeInstance.prototype.expectConnectionDeclined = function () { + var _ref7 = _asyncToGenerator(function* () { + console.log('[test]', 'Checking upgrade is not possible'); + var upgradeRequest = yield this.sendUpgradeRequest(); + return new Promise(function (resolve, reject) { + upgradeRequest.on('upgrade', common.mustNotCall('Upgrade was received')).on('response', function (response) { + return response.on('data', function () {}).on('end', function () { + return resolve(response.statusCode); + }); + }); + }); + }); + + function expectConnectionDeclined() { + return _ref7.apply(this, arguments); + } + + return expectConnectionDeclined; + }(); NodeInstance.prototype.expectShutdown = function expectShutdown() { return this._shutdownPromise; @@ -497,16 +593,26 @@ var NodeInstance = function () { }); }; + NodeInstance.prototype.write = function write(message) { + this._process.stdin.write(message); + }; + NodeInstance.prototype.kill = function kill() { this._process.kill(); + return this.expectShutdown(); }; - return NodeInstance; -}(); + NodeInstance.prototype.scriptPath = function scriptPath() { + return this._scriptPath; + }; -function readMainScriptSource() { - return fs.readFileSync(_MAINSCRIPT, 'utf8'); -} + NodeInstance.prototype.script = function script() { + if (this._script === null) this._script = fs.readFileSync(this.scriptPath(), 'utf8'); + return this._script; + }; + + return NodeInstance; +}(EventEmitter); function onResolvedOrRejected(promise, callback) { return promise.then(function (result) { @@ -548,8 +654,6 @@ function fires(promise, error, timeoutMs) { } module.exports = { - mainScriptPath: _MAINSCRIPT, - readMainScriptSource: readMainScriptSource, NodeInstance: NodeInstance }; diff --git a/test/common/internet.js b/test/common/internet.js new file mode 100644 index 0000000000..7e596a185b --- /dev/null +++ b/test/common/internet.js @@ -0,0 +1,97 @@ +'use strict'; + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/ /* eslint-disable node-core/required-modules */ +'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +// Utilities for internet-related tests + +var addresses = { + // A generic host that has registered common DNS records, + // supports both IPv4 and IPv6, and provides basic HTTP/HTTPS services + INET_HOST: 'nodejs.org', + // A host that provides IPv4 services + INET4_HOST: 'nodejs.org', + // A host that provides IPv6 services + INET6_HOST: 'nodejs.org', + // An accessible IPv4 IP, + // defaults to the Google Public DNS IPv4 address + INET4_IP: '8.8.8.8', + // An accessible IPv6 IP, + // defaults to the Google Public DNS IPv6 address + INET6_IP: '2001:4860:4860::8888', + // An invalid host that cannot be resolved + // See https://tools.ietf.org/html/rfc2606#section-2 + INVALID_HOST: 'something.invalid', + // A host with MX records registered + MX_HOST: 'nodejs.org', + // A host with SRV records registered + SRV_HOST: '_jabber._tcp.google.com', + // A host with PTR records registered + PTR_HOST: '8.8.8.8.in-addr.arpa', + // A host with NAPTR records registered + NAPTR_HOST: 'sip2sip.info', + // A host with SOA records registered + SOA_HOST: 'nodejs.org', + // A host with CNAME records registered + CNAME_HOST: 'blog.nodejs.org', + // A host with NS records registered + NS_HOST: 'nodejs.org', + // A host with TXT records registered + TXT_HOST: 'nodejs.org', + // An accessible IPv4 DNS server + DNS4_SERVER: '8.8.8.8', + // An accessible IPv4 DNS server + DNS6_SERVER: '2001:4860:4860::8888' +}; + +var _iteratorNormalCompletion = true; +var _didIteratorError = false; +var _iteratorError = undefined; + +try { + for (var _iterator = objectKeys(addresses)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var key = _step.value; + + var envName = 'NODE_TEST_' + key; + if (process.env[envName]) { + addresses[key] = process.env[envName]; + } + } +} catch (err) { + _didIteratorError = true; + _iteratorError = err; +} finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } +} + +module.exports = { + addresses: addresses +}; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/shared-lib-util.js b/test/common/shared-lib-util.js new file mode 100644 index 0000000000..399b9bdf50 --- /dev/null +++ b/test/common/shared-lib-util.js @@ -0,0 +1,60 @@ +'use strict'; + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +var common = require('../common'); +var path = require('path'); + +// If node executable is linked to shared lib, need to take care about the +// shared lib path. +exports.addLibraryPath = function (env) { + if (!process.config.variables.node_shared) { + return; + } + + env = env || process.env; + + env.LD_LIBRARY_PATH = (env.LD_LIBRARY_PATH ? env.LD_LIBRARY_PATH + path.delimiter : '') + path.join(path.dirname(process.execPath), 'lib.target'); + // For AIX. + env.LIBPATH = (env.LIBPATH ? env.LIBPATH + path.delimiter : '') + path.join(path.dirname(process.execPath), 'lib.target'); + // For Mac OSX. + env.DYLD_LIBRARY_PATH = (env.DYLD_LIBRARY_PATH ? env.DYLD_LIBRARY_PATH + path.delimiter : '') + path.dirname(process.execPath); + // For Windows. + env.PATH = (env.PATH ? env.PATH + path.delimiter : '') + path.dirname(process.execPath); +}; + +// Get the full path of shared lib. +exports.getSharedLibPath = function () { + if (common.isWindows) { + return path.join(path.dirname(process.execPath), 'node.dll'); + } else if (common.isOSX) { + return path.join(path.dirname(process.execPath), 'libnode.' + process.config.variables.shlib_suffix); + } else { + return path.join(path.dirname(process.execPath), 'lib.target', 'libnode.' + process.config.variables.shlib_suffix); + } +}; + +// Get the binary path of stack frames. +exports.getBinaryPath = function () { + return process.config.variables.node_shared ? exports.getSharedLibPath() : process.execPath; +}; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/tls.js b/test/common/tls.js new file mode 100644 index 0000000000..577dc4cc73 --- /dev/null +++ b/test/common/tls.js @@ -0,0 +1,200 @@ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/ /* eslint-disable node-core/required-modules, node-core/crypto-check */ + +'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +var crypto = require('crypto'); +var net = require('net'); + +exports.ccs = Buffer.from('140303000101', 'hex'); + +var TestTLSSocket = function (_net$Socket) { + _inherits(TestTLSSocket, _net$Socket); + + function TestTLSSocket(server_cert) { + _classCallCheck(this, TestTLSSocket); + + var _this = _possibleConstructorReturn(this, _net$Socket.call(this)); + + _this.server_cert = server_cert; + _this.version = Buffer.from('0303', 'hex'); + _this.handshake_list = []; + // AES128-GCM-SHA256 + _this.ciphers = Buffer.from('000002009c0', 'hex'); + _this.pre_master_secret = Buffer.concat([_this.version, crypto.randomBytes(46)]); + _this.master_secret = null; + _this.write_seq = 0; + _this.client_random = crypto.randomBytes(32); + + _this.on('handshake', function (msg) { + _this.handshake_list.push(msg); + }); + + _this.on('server_random', function (server_random) { + _this.master_secret = PRF12('sha256', _this.pre_master_secret, 'master secret', Buffer.concat([_this.client_random, server_random]), 48); + var key_block = PRF12('sha256', _this.master_secret, 'key expansion', Buffer.concat([server_random, _this.client_random]), 40); + _this.client_writeKey = key_block.slice(0, 16); + _this.client_writeIV = key_block.slice(32, 36); + }); + return _this; + } + + TestTLSSocket.prototype.createClientHello = function createClientHello() { + var compressions = Buffer.from('0100', 'hex'); // null + var msg = addHandshakeHeader(0x01, Buffer.concat([this.version, this.client_random, this.ciphers, compressions])); + this.emit('handshake', msg); + return addRecordHeader(0x16, msg); + }; + + TestTLSSocket.prototype.createClientKeyExchange = function createClientKeyExchange() { + var encrypted_pre_master_secret = crypto.publicEncrypt({ + key: this.server_cert, + padding: crypto.constants.RSA_PKCS1_PADDING + }, this.pre_master_secret); + var length = Buffer.alloc(2); + length.writeUIntBE(encrypted_pre_master_secret.length, 0, 2); + var msg = addHandshakeHeader(0x10, Buffer.concat([length, encrypted_pre_master_secret])); + this.emit('handshake', msg); + return addRecordHeader(0x16, msg); + }; + + TestTLSSocket.prototype.createFinished = function createFinished() { + var shasum = crypto.createHash('sha256'); + shasum.update(Buffer.concat(this.handshake_list)); + var message_hash = shasum.digest(); + var r = PRF12('sha256', this.master_secret, 'client finished', message_hash, 12); + var msg = addHandshakeHeader(0x14, r); + this.emit('handshake', msg); + return addRecordHeader(0x16, msg); + }; + + TestTLSSocket.prototype.createIllegalHandshake = function createIllegalHandshake() { + var illegal_handshake = Buffer.alloc(5); + return addRecordHeader(0x16, illegal_handshake); + }; + + TestTLSSocket.prototype.parseTLSFrame = function parseTLSFrame(buf) { + var offset = 0; + var record = buf.slice(offset, 5); + var type = record[0]; + var length = record.slice(3, 5).readUInt16BE(0); + offset += 5; + var remaining = buf.slice(offset, offset + length); + if (type === 0x16) { + do { + remaining = this.parseTLSHandshake(remaining); + } while (remaining.length > 0); + } + offset += length; + return buf.slice(offset); + }; + + TestTLSSocket.prototype.parseTLSHandshake = function parseTLSHandshake(buf) { + var offset = 0; + var handshake_type = buf[offset]; + if (handshake_type === 0x02) { + var server_random = buf.slice(6, 6 + 32); + this.emit('server_random', server_random); + } + offset += 1; + var length = buf.readUIntBE(offset, 3); + offset += 3; + var handshake = buf.slice(0, offset + length); + this.emit('handshake', handshake); + offset += length; + var remaining = buf.slice(offset); + return remaining; + }; + + TestTLSSocket.prototype.encrypt = function encrypt(plain) { + var type = plain.slice(0, 1); + var version = plain.slice(1, 3); + var nonce = crypto.randomBytes(8); + var iv = Buffer.concat([this.client_writeIV.slice(0, 4), nonce]); + var bob = crypto.createCipheriv('aes-128-gcm', this.client_writeKey, iv); + var write_seq = Buffer.alloc(8); + write_seq.writeUInt32BE(this.write_seq++, 4); + var aad = Buffer.concat([write_seq, plain.slice(0, 5)]); + bob.setAAD(aad); + var encrypted1 = bob.update(plain.slice(5)); + var encrypted = Buffer.concat([encrypted1, bob.final()]); + var tag = bob.getAuthTag(); + var length = Buffer.alloc(2); + length.writeUInt16BE(nonce.length + encrypted.length + tag.length, 0); + return Buffer.concat([type, version, length, nonce, encrypted, tag]); + }; + + return TestTLSSocket; +}(net.Socket); + +function addRecordHeader(type, frame) { + var record_layer = Buffer.from('0003030000', 'hex'); + record_layer[0] = type; + record_layer.writeUInt16BE(frame.length, 3); + return Buffer.concat([record_layer, frame]); +} + +function addHandshakeHeader(type, msg) { + var handshake_header = Buffer.alloc(4); + handshake_header[0] = type; + handshake_header.writeUIntBE(msg.length, 1, 3); + return Buffer.concat([handshake_header, msg]); +} + +function PRF12(algo, secret, label, seed, size) { + var newSeed = Buffer.concat([Buffer.from(label, 'utf8'), seed]); + return P_hash(algo, secret, newSeed, size); +} + +function P_hash(algo, secret, seed, size) { + var result = Buffer.alloc(size); + var hmac = crypto.createHmac(algo, secret); + hmac.update(seed); + var a = hmac.digest(); + var j = 0; + while (j < size) { + hmac = crypto.createHmac(algo, secret); + hmac.update(a); + hmac.update(seed); + var b = hmac.digest(); + var todo = b.length; + if (j + todo > size) { + todo = size - j; + } + b.copy(result, j, 0, todo); + j += todo; + hmac = crypto.createHmac(algo, secret); + hmac.update(a); + a = hmac.digest(); + } + return result; +} + +exports.TestTLSSocket = TestTLSSocket; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/tmpdir.js b/test/common/tmpdir.js new file mode 100644 index 0000000000..eb17dbbcc4 --- /dev/null +++ b/test/common/tmpdir.js @@ -0,0 +1,80 @@ +'use strict'; + +/**/ +require('babel-polyfill'); +var util = require('util'); +for (var i in util) { + exports[i] = util[i]; +} /**/ /* eslint-disable node-core/required-modules */ +'use strict'; + +/**/ +var objectKeys = objectKeys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/**/ + +var fs = require('fs'); +var path = require('path'); + +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 = process.platform === 'linux' ? 'buffer' : 'utf8'; + forEach(fs.readdirSync(p, enc), 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); + } + } +} + +var testRoot = process.env.NODE_TEST_DIR ? fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..'); + +// Using a `.` prefixed name, which is the convention for "hidden" on POSIX, +// gets tools to ignore it by default or by simple rules, especially eslint. +var tmpdirName = '.tmp'; +if (process.env.TEST_THREAD_ID) { + tmpdirName += '.' + process.env.TEST_THREAD_ID; +} +exports.path = path.join(testRoot, tmpdirName); + +exports.refresh = function () { + rimrafSync(exports.path); + fs.mkdirSync(exports.path); +}; + +function forEach(xs, f) { + for (var i = 0, l = xs.length; i < l; i++) { + f(xs[i], i); + } +} \ No newline at end of file diff --git a/test/common/wpt.js b/test/common/wpt.js index 22a5c89709..0e45ab7e32 100644 --- a/test/common/wpt.js +++ b/test/common/wpt.js @@ -1,21 +1,11 @@ +'use strict'; + /**/ require('babel-polyfill'); var util = require('util'); for (var i in util) { exports[i] = util[i]; -} /**/ /**/ -if (!global.setImmediate) { - global.setImmediate = function setImmediate(fn) { - return setTimeout(fn.bind.apply(fn, arguments), 4); - }; -} -if (!global.clearImmediate) { - global.clearImmediate = function clearImmediate(i) { - return clearTimeout(i); - }; -} -/**/ -/* eslint-disable required-modules */ +} /**/ /* eslint-disable node-core/required-modules */ 'use strict'; /**/ diff --git a/test/ours/lolex-fake-timers.js b/test/ours/lolex-fake-timers.js index c1b883d4b7..59af1328ea 100644 --- a/test/ours/lolex-fake-timers.js +++ b/test/ours/lolex-fake-timers.js @@ -1,4 +1,5 @@ require('../common'); +var tap = require('tap'); var util = require('util'); var assert = require('assert'); var lolex = require('lolex'); @@ -37,3 +38,4 @@ stream.emit('data'); clock.runAll() clock.uninstall(); assert(stream2DataCalled); +tap.pass('ok'); diff --git a/test/ours/test-stream-sync-write.js b/test/ours/test-stream-sync-write.js index f0a08f53e8..bfa7be9410 100644 --- a/test/ours/test-stream-sync-write.js +++ b/test/ours/test-stream-sync-write.js @@ -34,3 +34,5 @@ var externalStream = new ExternalStream(internalStream); for (var i = 0; i < 2000; i++) { externalStream.write(i.toString()); } + +require('tap').pass('sync done'); diff --git a/test/parallel/test-stream-backpressure.js b/test/parallel/test-stream-backpressure.js new file mode 100644 index 0000000000..14e12bc1ba --- /dev/null +++ b/test/parallel/test-stream-backpressure.js @@ -0,0 +1,46 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); +var assert = require('assert/'); +var stream = require('../../'); + +var pushes = 0; +var total = 65500 + 40 * 1024; +var rs = new stream.Readable({ + read: common.mustCall(function () { + if (pushes++ === 10) { + this.push(null); + return; + } + + var length = this._readableState.length; + + // We are at most doing two full runs of _reads + // before stopping, because Readable is greedy + // to keep its buffer full + assert(length <= total); + + this.push(bufferShim.alloc(65500)); + for (var i = 0; i < 40; i++) { + this.push(bufferShim.alloc(1024)); + } + + // We will be over highWaterMark at this point + // but a new call to _read is scheduled anyway. + }, 11) +}); + +var ws = stream.Writable({ + write: common.mustCall(function (data, enc, cb) { + setImmediate(cb); + }, 41 * 10) +}); + +rs.pipe(ws); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-big-packet.js b/test/parallel/test-stream-big-packet.js index 85de251100..9480fdf5c4 100644 --- a/test/parallel/test-stream-big-packet.js +++ b/test/parallel/test-stream-big-packet.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -83,4 +85,7 @@ function indexOf(xs, x) { if (xs[i] === x) return i; } return -1; -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-big-push.js b/test/parallel/test-stream-big-push.js index 68835fe5fb..81baa7ba47 100644 --- a/test/parallel/test-stream-big-push.js +++ b/test/parallel/test-stream-big-push.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -73,4 +75,7 @@ r.once('readable', function () { chunk = r.read(); assert.strictEqual(chunk, null); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-buffer-list.js b/test/parallel/test-stream-buffer-list.js index 531658e81e..393de025d2 100644 --- a/test/parallel/test-stream-buffer-list.js +++ b/test/parallel/test-stream-buffer-list.js @@ -1,10 +1,12 @@ +'use strict'; + // Flags: --expose_internals /**/ var bufferShim = require('safe-buffer').Buffer; /**/ require('../common'); var assert = require('assert/'); -var BufferList = require('../../lib/internal/streams/BufferList'); +var BufferList = require('../../lib/internal/streams/buffer_list'); // Test empty buffer list. var emptyList = new BufferList(); @@ -16,14 +18,22 @@ assert.strictEqual(emptyList.join(','), ''); assert.deepStrictEqual(emptyList.concat(0), bufferShim.alloc(0)); +var buf = bufferShim.from('foo'); + // Test buffer list with one element. var list = new BufferList(); -list.push('foo'); +list.push(buf); + +var copy = list.concat(3); -assert.strictEqual(list.concat(1), 'foo'); +assert.notStrictEqual(copy, buf); +assert.deepStrictEqual(copy, buf); assert.strictEqual(list.join(','), 'foo'); var shifted = list.shift(); -assert.strictEqual(shifted, 'foo'); -assert.deepStrictEqual(list, new BufferList()); \ No newline at end of file +assert.strictEqual(shifted, buf); +assert.deepStrictEqual(list, new BufferList()); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-decoder-objectmode.js b/test/parallel/test-stream-decoder-objectmode.js index b875a0f07d..b10de29754 100644 --- a/test/parallel/test-stream-decoder-objectmode.js +++ b/test/parallel/test-stream-decoder-objectmode.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -19,4 +21,7 @@ readable.push(null); // Without object mode, these would be concatenated into a single chunk. assert.strictEqual(readable.read(), 'abc'); assert.strictEqual(readable.read(), 'def'); -assert.strictEqual(readable.read(), null); \ No newline at end of file +assert.strictEqual(readable.read(), null); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-destroy-event-order.js b/test/parallel/test-stream-destroy-event-order.js new file mode 100644 index 0000000000..133703b47b --- /dev/null +++ b/test/parallel/test-stream-destroy-event-order.js @@ -0,0 +1,33 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); +var assert = require('assert/'); + +var _require = require('../../'), + Readable = _require.Readable; + +var rs = new Readable({ + read: function () {} +}); + +var closed = false; +var errored = false; + +rs.on('close', common.mustCall(function () { + closed = true; + assert(errored); +})); + +rs.on('error', common.mustCall(function (err) { + errored = true; + assert(!closed); +})); + +rs.destroy(new Error('kaboom')); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-duplex-destroy.js b/test/parallel/test-stream-duplex-destroy.js index 2ac6fcba27..71187bd1ac 100644 --- a/test/parallel/test-stream-duplex-destroy.js +++ b/test/parallel/test-stream-duplex-destroy.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -22,8 +24,9 @@ var _require2 = require('util'), duplex.resume(); - duplex.on('end', common.mustCall()); - duplex.on('finish', common.mustCall()); + duplex.on('end', common.mustNotCall()); + duplex.on('finish', common.mustNotCall()); + duplex.on('close', common.mustCall()); duplex.destroy(); assert.strictEqual(duplex.destroyed, true); @@ -40,8 +43,8 @@ var _require2 = require('util'), var expected = new Error('kaboom'); - _duplex.on('end', common.mustCall()); - _duplex.on('finish', common.mustCall()); + _duplex.on('end', common.mustNotCall()); + _duplex.on('finish', common.mustNotCall()); _duplex.on('error', common.mustCall(function (err) { assert.strictEqual(err, expected); })); @@ -94,6 +97,7 @@ var _require2 = require('util'), // error is swallowed by the custom _destroy _duplex3.on('error', common.mustNotCall('no error event')); + _duplex3.on('close', common.mustCall()); _duplex3.destroy(_expected2); assert.strictEqual(_duplex3.destroyed, true); @@ -186,8 +190,8 @@ var _require2 = require('util'), }); _duplex7.resume(); - _duplex7.on('finish', common.mustCall()); - _duplex7.on('end', common.mustCall()); + _duplex7.on('finish', common.mustNotCall()); + _duplex7.on('end', common.mustNotCall()); _duplex7.destroy(); assert.strictEqual(_duplex7.destroyed, true); @@ -220,4 +224,7 @@ var _require2 = require('util'), inherits(MyDuplex, Duplex); new MyDuplex(); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-duplex-end.js b/test/parallel/test-stream-duplex-end.js new file mode 100644 index 0000000000..95754b424d --- /dev/null +++ b/test/parallel/test-stream-duplex-end.js @@ -0,0 +1,50 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); +var assert = require('assert/'); +var Duplex = require('../../').Duplex; + +{ + var stream = new Duplex({ + read: function () {} + }); + assert.strictEqual(stream.allowHalfOpen, true); + stream.on('finish', common.mustNotCall()); + assert.strictEqual(stream.listenerCount('end'), 0); + stream.resume(); + stream.push(null); +} + +{ + var _stream = new Duplex({ + read: function () {}, + + allowHalfOpen: false + }); + assert.strictEqual(_stream.allowHalfOpen, false); + _stream.on('finish', common.mustCall()); + assert.strictEqual(_stream.listenerCount('end'), 1); + _stream.resume(); + _stream.push(null); +} + +{ + var _stream2 = new Duplex({ + read: function () {}, + + allowHalfOpen: false + }); + assert.strictEqual(_stream2.allowHalfOpen, false); + _stream2._writableState.ended = true; + _stream2.on('finish', common.mustNotCall()); + assert.strictEqual(_stream2.listenerCount('end'), 1); + _stream2.resume(); + _stream2.push(null); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-duplex.js b/test/parallel/test-stream-duplex.js index 9b121ca2ac..4e54d7d38c 100644 --- a/test/parallel/test-stream-duplex.js +++ b/test/parallel/test-stream-duplex.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -31,6 +33,8 @@ var stream = new Duplex({ objectMode: true }); assert(Duplex() instanceof Duplex); assert(stream._readableState.objectMode); assert(stream._writableState.objectMode); +assert(stream.allowHalfOpen); +assert.strictEqual(stream.listenerCount('end'), 0); var written = void 0; var read = void 0; @@ -52,4 +56,7 @@ stream.end({ val: 2 }); process.on('exit', function () { assert.strictEqual(read.val, 1); assert.strictEqual(written.val, 2); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-end-paused.js b/test/parallel/test-stream-end-paused.js index eeea575920..f9c4584da2 100644 --- a/test/parallel/test-stream-end-paused.js +++ b/test/parallel/test-stream-end-paused.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -48,5 +50,7 @@ setTimeout(common.mustCall(function () { process.on('exit', function () { assert(calledRead); - console.log('ok'); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-events-prepend.js b/test/parallel/test-stream-events-prepend.js index b6d36d219f..7cdb62d096 100644 --- a/test/parallel/test-stream-events-prepend.js +++ b/test/parallel/test-stream-events-prepend.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -49,4 +51,7 @@ var w = new Writable(); w.on('pipe', common.mustCall()); var r = new Readable(); -r.pipe(w); \ No newline at end of file +r.pipe(w); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-finished.js b/test/parallel/test-stream-finished.js new file mode 100644 index 0000000000..90a375b40b --- /dev/null +++ b/test/parallel/test-stream-finished.js @@ -0,0 +1,142 @@ +'use strict'; + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); + +var _require = require('../../'), + Writable = _require.Writable, + Readable = _require.Readable, + Transform = _require.Transform, + finished = _require.finished; + +var assert = require('assert/'); +var fs = require('fs'); +var promisify = require('util-promisify'); + +{ + var rs = new Readable({ + read: function () {} + }); + + finished(rs, common.mustCall(function (err) { + assert(!err, 'no error'); + })); + + rs.push(null); + rs.resume(); +} + +{ + var ws = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + finished(ws, common.mustCall(function (err) { + assert(!err, 'no error'); + })); + + ws.end(); +} + +{ + var tr = new Transform({ + transform: function (data, enc, cb) { + cb(); + } + }); + + var finish = false; + var ended = false; + + tr.on('end', function () { + ended = true; + }); + + tr.on('finish', function () { + finish = true; + }); + + finished(tr, common.mustCall(function (err) { + assert(!err, 'no error'); + assert(finish); + assert(ended); + })); + + tr.end(); + tr.resume(); +} + +{ + var _rs = fs.createReadStream(__filename); + + _rs.resume(); + finished(_rs, common.mustCall()); +} + +{ + var run = function () { + var _ref = _asyncToGenerator(function* () { + var rs = fs.createReadStream(__filename); + var done = common.mustCall(); + + var ended = false; + rs.resume(); + rs.on('end', function () { + ended = true; + }); + yield finishedPromise(rs); + assert(ended); + done(); + }); + + return function run() { + return _ref.apply(this, arguments); + }; + }(); + + var finishedPromise = promisify(finished); + + run(); +} + +{ + var _rs2 = fs.createReadStream('file-does-not-exist'); + + finished(_rs2, common.mustCall(function (err) { + assert.strictEqual(err.code, 'ENOENT'); + })); +} + +{ + var _rs3 = new Readable(); + + finished(_rs3, common.mustCall(function (err) { + assert(!err, 'no error'); + })); + + _rs3.push(null); + _rs3.emit('close'); // should not trigger an error + _rs3.resume(); +} + +{ + var _rs4 = new Readable(); + + finished(_rs4, common.mustCall(function (err) { + assert(err, 'premature close error'); + })); + + _rs4.emit('close'); // should trigger error + _rs4.push(null); + _rs4.resume(); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-ispaused.js b/test/parallel/test-stream-ispaused.js index 6abb10fc13..4ecf700a4e 100644 --- a/test/parallel/test-stream-ispaused.js +++ b/test/parallel/test-stream-ispaused.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -43,4 +45,7 @@ assert.ok(!readable.isPaused()); readable.pause(); assert.ok(readable.isPaused()); readable.resume(); -assert.ok(!readable.isPaused()); \ No newline at end of file +assert.ok(!readable.isPaused()); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-objectmode-undefined.js b/test/parallel/test-stream-objectmode-undefined.js index d1f5a0c700..72e34c0757 100644 --- a/test/parallel/test-stream-objectmode-undefined.js +++ b/test/parallel/test-stream-objectmode-undefined.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -47,4 +49,7 @@ var _require = require('../../'), })); _stream2.write(undefined); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-after-end.js b/test/parallel/test-stream-pipe-after-end.js index c9ed1aa721..6a289c9457 100644 --- a/test/parallel/test-stream-pipe-after-end.js +++ b/test/parallel/test-stream-pipe-after-end.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -92,4 +94,7 @@ setTimeout(common.mustCall(function () { var w = new TestWritable(); w.on('finish', common.mustCall()); piper.pipe(w); -}), 1); \ No newline at end of file +}), 1); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-await-drain-manual-resume.js b/test/parallel/test-stream-pipe-await-drain-manual-resume.js index 3475d3528e..5d605a4a1a 100644 --- a/test/parallel/test-stream-pipe-await-drain-manual-resume.js +++ b/test/parallel/test-stream-pipe-await-drain-manual-resume.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -77,4 +79,7 @@ readable.push(null); writable.on('finish', common.mustCall(function () { assert.strictEqual(readable._readableState.awaitDrain, 0, 'awaitDrain should equal 0 after all chunks are written but instead got' + ('' + readable._readableState.awaitDrain)); // Everything okay, all chunks were written. -})); \ No newline at end of file +})); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-await-drain-push-while-write.js b/test/parallel/test-stream-pipe-await-drain-push-while-write.js index 7dc8de43a6..2ee2ce1afb 100644 --- a/test/parallel/test-stream-pipe-await-drain-push-while-write.js +++ b/test/parallel/test-stream-pipe-await-drain-push-while-write.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -5,27 +7,20 @@ var common = require('../common'); var stream = require('../../'); var assert = require('assert/'); -var awaitDrainStates = [1, // after first chunk before callback -1, // after second chunk before callback -0 // resolving chunk pushed after first chunk, awaitDrain is decreased -]; - -// A writable stream which pushes data onto the stream which pipes into it, -// but only the first time it's written to. Since it's not paused at this time, -// a second write will occur. If the pipe increases awaitDrain twice, we'll -// never get subsequent chunks because 'drain' is only emitted once. var writable = new stream.Writable({ write: common.mustCall(function (chunk, encoding, cb) { + assert.strictEqual(readable._readableState.awaitDrain, 0); + if (chunk.length === 32 * 1024) { // first chunk - var beforePush = readable._readableState.awaitDrain; readable.push(bufferShim.alloc(34 * 1024)); // above hwm - // We should check if awaitDrain counter is increased. - var afterPush = readable._readableState.awaitDrain; - assert.strictEqual(afterPush - beforePush, 1, 'Counter is not increased for awaitDrain'); + // We should check if awaitDrain counter is increased in the next + // tick, because awaitDrain is incremented after this method finished + process.nextTick(function () { + assert.strictEqual(readable._readableState.awaitDrain, 1); + }); } - assert.strictEqual(awaitDrainStates.shift(), readable._readableState.awaitDrain, 'State variable awaitDrain is not correct.'); cb(); }, 3) }); @@ -40,4 +35,7 @@ var readable = new stream.Readable({ } }); -readable.pipe(writable); \ No newline at end of file +readable.pipe(writable); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-await-drain.js b/test/parallel/test-stream-pipe-await-drain.js index 55cc714489..35bf348888 100644 --- a/test/parallel/test-stream-pipe-await-drain.js +++ b/test/parallel/test-stream-pipe-await-drain.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -25,7 +27,7 @@ writer1._write = common.mustCall(function (chunk, encoding, cb) { }, 1); writer1.once('chunk-received', function () { - assert.strictEqual(reader._readableState.awaitDrain, 0, 'initial value is not 0'); + assert.strictEqual(reader._readableState.awaitDrain, 0, 'awaitDrain initial value should be 0, actual is ' + reader._readableState.awaitDrain); setImmediate(function () { // This one should *not* get through to writer1 because writer2 is not // "done" processing. @@ -35,14 +37,14 @@ writer1.once('chunk-received', function () { // A "slow" consumer: writer2._write = common.mustCall(function (chunk, encoding, cb) { - assert.strictEqual(reader._readableState.awaitDrain, 1, 'awaitDrain isn\'t 1 after first push'); + assert.strictEqual(reader._readableState.awaitDrain, 1, 'awaitDrain should be 1 after first push, actual is ' + reader._readableState.awaitDrain); // Not calling cb here to "simulate" slow stream. // This should be called exactly once, since the first .write() call // will return false. }, 1); writer3._write = common.mustCall(function (chunk, encoding, cb) { - assert.strictEqual(reader._readableState.awaitDrain, 2, 'awaitDrain isn\'t 2 after second push'); + assert.strictEqual(reader._readableState.awaitDrain, 2, 'awaitDrain should be 2 after second push, actual is ' + reader._readableState.awaitDrain); // Not calling cb here to "simulate" slow stream. // This should be called exactly once, since the first .write() call // will return false. @@ -51,4 +53,7 @@ writer3._write = common.mustCall(function (chunk, encoding, cb) { reader.pipe(writer1); reader.pipe(writer2); reader.pipe(writer3); -reader.push(buffer); \ No newline at end of file +reader.push(buffer); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-cleanup-pause.js b/test/parallel/test-stream-pipe-cleanup-pause.js index 6aad21ed15..8e1cbc02ff 100644 --- a/test/parallel/test-stream-pipe-cleanup-pause.js +++ b/test/parallel/test-stream-pipe-cleanup-pause.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -36,4 +38,7 @@ writer2._write = common.mustCall(function (chunk, encoding, cb) { }, 3); reader.pipe(writer1); -reader.push(buffer); \ No newline at end of file +reader.push(buffer); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-cleanup.js b/test/parallel/test-stream-pipe-cleanup.js index e7151796f4..c16f1c629a 100644 --- a/test/parallel/test-stream-pipe-cleanup.js +++ b/test/parallel/test-stream-pipe-cleanup.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -126,4 +128,6 @@ var util = require('util'); assert.strictEqual(d.listeners('close').length, 0); assert.strictEqual(w.listeners('end').length, 0); assert.strictEqual(w.listeners('close').length, 0); -})(); \ No newline at end of file +})();require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-error-handling.js b/test/parallel/test-stream-pipe-error-handling.js index f6040812c9..de2b824fb6 100644 --- a/test/parallel/test-stream-pipe-error-handling.js +++ b/test/parallel/test-stream-pipe-error-handling.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -109,4 +111,7 @@ var Stream = require('stream').Stream; // Removing some OTHER random listener should not do anything _w.removeListener('error', function () {}); _removed = true; -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-event.js b/test/parallel/test-stream-pipe-event.js index ebe373e7d6..ac761c86b4 100644 --- a/test/parallel/test-stream-pipe-event.js +++ b/test/parallel/test-stream-pipe-event.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -49,4 +51,7 @@ w.on('pipe', function (src) { var r = new Readable(); r.pipe(w); -assert.ok(passed); \ No newline at end of file +assert.ok(passed); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-flow-after-unpipe.js b/test/parallel/test-stream-pipe-flow-after-unpipe.js new file mode 100644 index 0000000000..9c7fa184af --- /dev/null +++ b/test/parallel/test-stream-pipe-flow-after-unpipe.js @@ -0,0 +1,42 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ +var common = require('../common'); + +var _require = require('../../'), + Readable = _require.Readable, + Writable = _require.Writable; + +// Tests that calling .unpipe() un-blocks a stream that is paused because +// it is waiting on the writable side to finish a write(). + +var rs = new Readable({ + highWaterMark: 1, + // That this gets called at least 20 times is the real test here. + read: common.mustCallAtLeast(function () { + return rs.push('foo'); + }, 20) +}); + +var ws = new Writable({ + highWaterMark: 1, + write: common.mustCall(function () { + // Ignore the callback, this write() simply never finishes. + setImmediate(function () { + return rs.unpipe(ws); + }); + }) +}); + +var chunks = 0; +rs.on('data', common.mustCallAtLeast(function () { + chunks++; + if (chunks >= 20) rs.pause(); // Finish this test. +})); + +rs.pipe(ws); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-flow.js b/test/parallel/test-stream-pipe-flow.js new file mode 100644 index 0000000000..b651f3902b --- /dev/null +++ b/test/parallel/test-stream-pipe-flow.js @@ -0,0 +1,78 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ +var common = require('../common'); + +var _require = require('../../'), + Readable = _require.Readable, + Writable = _require.Writable, + PassThrough = _require.PassThrough; + +{ + var ticks = 17; + + var rs = new Readable({ + objectMode: true, + read: function () { + if (ticks-- > 0) return process.nextTick(function () { + return rs.push({}); + }); + rs.push({}); + rs.push(null); + } + }); + + var ws = new Writable({ + highWaterMark: 0, + objectMode: true, + write: function (data, end, cb) { + return setImmediate(cb); + } + }); + + rs.on('end', common.mustCall()); + ws.on('finish', common.mustCall()); + rs.pipe(ws); +} + +{ + var missing = 8; + + var _rs = new Readable({ + objectMode: true, + read: function () { + if (missing--) _rs.push({});else _rs.push(null); + } + }); + + var pt = _rs.pipe(new PassThrough({ objectMode: true, highWaterMark: 2 })).pipe(new PassThrough({ objectMode: true, highWaterMark: 2 })); + + pt.on('end', function () { + wrapper.push(null); + }); + + var wrapper = new Readable({ + objectMode: true, + read: function () { + process.nextTick(function () { + var data = pt.read(); + if (data === null) { + pt.once('readable', function () { + data = pt.read(); + if (data !== null) wrapper.push(data); + }); + } else { + wrapper.push(data); + } + }); + } + }); + + wrapper.resume(); + wrapper.on('end', common.mustCall()); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-manual-resume.js b/test/parallel/test-stream-pipe-manual-resume.js new file mode 100644 index 0000000000..d6d7051fc7 --- /dev/null +++ b/test/parallel/test-stream-pipe-manual-resume.js @@ -0,0 +1,47 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ +var common = require('../common'); +var stream = require('../../'); + +function test(throwCodeInbetween) { + // Check that a pipe does not stall if .read() is called unexpectedly + // (i.e. the stream is not resumed by the pipe). + + var n = 1000; + var counter = n; + var rs = stream.Readable({ + objectMode: true, + read: common.mustCallAtLeast(function () { + if (--counter >= 0) rs.push({ counter: counter });else rs.push(null); + }, n) + }); + + var ws = stream.Writable({ + objectMode: true, + write: common.mustCall(function (data, enc, cb) { + setImmediate(cb); + }, n) + }); + + setImmediate(function () { + return throwCodeInbetween(rs, ws); + }); + + rs.pipe(ws); +} + +test(function (rs) { + return rs.read(); +}); +test(function (rs) { + return rs.resume(); +}); +test(function () { + return 0; +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-multiple-pipes.js b/test/parallel/test-stream-pipe-multiple-pipes.js index 21abfcf18e..71952b4575 100644 --- a/test/parallel/test-stream-pipe-multiple-pipes.js +++ b/test/parallel/test-stream-pipe-multiple-pipes.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -95,4 +97,7 @@ readable.on('end', common.mustCall(function () { } } } -})); \ No newline at end of file +})); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-same-destination-twice.js b/test/parallel/test-stream-pipe-same-destination-twice.js index f3c0c895b3..9f77baf20b 100644 --- a/test/parallel/test-stream-pipe-same-destination-twice.js +++ b/test/parallel/test-stream-pipe-same-destination-twice.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -80,4 +82,7 @@ var _require = require('../../'), assert.strictEqual(_passThrough2._readableState.pipesCount, 0); _passThrough2.write('foobar'); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-unpipe-streams.js b/test/parallel/test-stream-pipe-unpipe-streams.js index 6cc3a10491..72ab9ea851 100644 --- a/test/parallel/test-stream-pipe-unpipe-streams.js +++ b/test/parallel/test-stream-pipe-unpipe-streams.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -34,4 +36,49 @@ source.unpipe(dest2); source.unpipe(dest1); -assert.strictEqual(source._readableState.pipes, null); \ No newline at end of file +assert.strictEqual(source._readableState.pipes, null); + +{ + // test `cleanup()` if we unpipe all streams. + var _source = Readable({ read: function () {} }); + var _dest = Writable({ write: function () {} }); + var _dest2 = Writable({ write: function () {} }); + + var destCount = 0; + var srcCheckEventNames = ['end', 'data']; + var destCheckEventNames = ['close', 'finish', 'drain', 'error', 'unpipe']; + + var checkSrcCleanup = common.mustCall(function () { + assert.strictEqual(_source._readableState.pipes, null); + assert.strictEqual(_source._readableState.pipesCount, 0); + assert.strictEqual(_source._readableState.flowing, false); + + srcCheckEventNames.forEach(function (eventName) { + assert.strictEqual(_source.listenerCount(eventName), 0, 'source\'s \'' + eventName + '\' event listeners not removed'); + }); + }); + + function checkDestCleanup(dest) { + var currentDestId = ++destCount; + _source.pipe(dest); + + var unpipeChecker = common.mustCall(function () { + assert.deepStrictEqual(dest.listeners('unpipe'), [unpipeChecker], 'destination{' + currentDestId + '} should have a \'unpipe\' event ' + 'listener which is `unpipeChecker`'); + dest.removeListener('unpipe', unpipeChecker); + destCheckEventNames.forEach(function (eventName) { + assert.strictEqual(dest.listenerCount(eventName), 0, 'destination{' + currentDestId + '}\'s \'' + eventName + '\' event ' + 'listeners not removed'); + }); + + if (--destCount === 0) checkSrcCleanup(); + }); + + dest.on('unpipe', unpipeChecker); + } + + checkDestCleanup(_dest); + checkDestCleanup(_dest2); + _source.unpipe(); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipe-without-listenerCount.js b/test/parallel/test-stream-pipe-without-listenerCount.js index 3bb5a9e4ef..8e4b437879 100644 --- a/test/parallel/test-stream-pipe-without-listenerCount.js +++ b/test/parallel/test-stream-pipe-without-listenerCount.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -16,4 +18,7 @@ w.on('pipe', function () { }); r.on('error', common.mustCall()); w.on('error', common.mustCall()); -r.pipe(w); \ No newline at end of file +r.pipe(w); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-pipeline.js b/test/parallel/test-stream-pipeline.js new file mode 100644 index 0000000000..d8021fc0b4 --- /dev/null +++ b/test/parallel/test-stream-pipeline.js @@ -0,0 +1,510 @@ +'use strict'; + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); +if (!common.hasCrypto) common.skip('missing crypto'); + +var _require = require('../../'), + Stream = _require.Stream, + Writable = _require.Writable, + Readable = _require.Readable, + Transform = _require.Transform, + pipeline = _require.pipeline; + +var assert = require('assert/'); +var http = require('http'); +var http2 = { + createServer: function () { + return { + listen: function () {} + }; + } +}; +var promisify = require('util-promisify'); + +{ + var finished = false; + var processed = []; + var expected = [bufferShim.from('a'), bufferShim.from('b'), bufferShim.from('c')]; + + var read = new Readable({ + read: function () {} + }); + + var write = new Writable({ + write: function (data, enc, cb) { + processed.push(data); + cb(); + } + }); + + write.on('finish', function () { + finished = true; + }); + + for (var i = 0; i < expected.length; i++) { + read.push(expected[i]); + } + read.push(null); + + pipeline(read, write, common.mustCall(function (err) { + assert.ok(!err, 'no error'); + assert.ok(finished); + assert.deepStrictEqual(processed, expected); + })); +} + +{ + var _read = new Readable({ + read: function () {} + }); + + assert.throws(function () { + pipeline(_read, function () {}); + }, /ERR_MISSING_ARGS/); + assert.throws(function () { + pipeline(function () {}); + }, /ERR_MISSING_ARGS/); + assert.throws(function () { + pipeline(); + }, /ERR_MISSING_ARGS/); +} + +{ + var _read2 = new Readable({ + read: function () {} + }); + + var _write = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + _read2.push('data'); + setImmediate(function () { + return _read2.destroy(); + }); + + pipeline(_read2, _write, common.mustCall(function (err) { + assert.ok(err, 'should have an error'); + })); +} + +{ + var _read3 = new Readable({ + read: function () {} + }); + + var _write2 = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + _read3.push('data'); + setImmediate(function () { + return _read3.destroy(new Error('kaboom')); + }); + + var dst = pipeline(_read3, _write2, common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + })); + + assert.strictEqual(dst, _write2); +} + +{ + var _read4 = new Readable({ + read: function () {} + }); + + var transform = new Transform({ + transform: function (data, enc, cb) { + process.nextTick(cb, new Error('kaboom')); + } + }); + + var _write3 = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + _read4.on('close', common.mustCall()); + transform.on('close', common.mustCall()); + _write3.on('close', common.mustCall()); + + var _dst = pipeline(_read4, transform, _write3, common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + })); + + assert.strictEqual(_dst, _write3); + + _read4.push('hello'); +} + +{ + var server = http.createServer(function (req, res) { + var rs = new Readable({ + read: function () { + rs.push('hello'); + rs.push(null); + } + }); + + pipeline(rs, res, function () {}); + }); + + server.listen(0, function () { + var req = http.request({ + port: server.address().port + }); + + req.end(); + req.on('response', function (res) { + var buf = []; + res.on('data', function (data) { + return buf.push(data); + }); + res.on('end', common.mustCall(function () { + assert.deepStrictEqual(Buffer.concat(buf), bufferShim.from('hello')); + server.close(); + })); + }); + }); +} + +{ + var _server = http.createServer(function (req, res) { + var rs = new Readable({ + read: function () { + rs.push('hello'); + }, + + destroy: common.mustCall(function (err, cb) { + // prevents fd leaks by destroying http pipelines + cb(); + }) + }); + + pipeline(rs, res, function () {}); + }); + + _server.listen(0, function () { + var req = http.request({ + port: _server.address().port + }); + + req.end(); + req.on('response', function (res) { + setImmediate(function () { + res.destroy(); + _server.close(); + }); + }); + }); +} + +{ + var _server2 = http.createServer(function (req, res) { + var rs = new Readable({ + read: function () { + rs.push('hello'); + }, + + destroy: common.mustCall(function (err, cb) { + cb(); + }) + }); + + pipeline(rs, res, function () {}); + }); + + var cnt = 10; + + var badSink = new Writable({ + write: function (data, enc, cb) { + cnt--; + if (cnt === 0) process.nextTick(cb, new Error('kaboom'));else cb(); + } + }); + + _server2.listen(0, function () { + var req = http.request({ + port: _server2.address().port + }); + + req.end(); + req.on('response', function (res) { + pipeline(res, badSink, common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + _server2.close(); + })); + }); + }); +} + +{ + var _server3 = http.createServer(function (req, res) { + pipeline(req, res, common.mustCall()); + }); + + _server3.listen(0, function () { + var req = http.request({ + port: _server3.address().port + }); + + var rs = new Readable({ + read: function () { + rs.push('hello'); + } + }); + + pipeline(rs, req, common.mustCall(function () { + _server3.close(); + })); + + req.on('response', function (res) { + var cnt = 10; + res.on('data', function () { + cnt--; + if (cnt === 0) rs.destroy(); + }); + }); + }); +} + +{ + var _server4 = http2.createServer(function (req, res) { + pipeline(req, res, common.mustCall()); + }); + + _server4.listen(0, function () { + var url = 'http://localhost:' + _server4.address().port; + var client = http2.connect(url); + var req = client.request({ ':method': 'POST' }); + + var rs = new Readable({ + read: function () { + rs.push('hello'); + } + }); + + pipeline(rs, req, common.mustCall(function (err) { + _server4.close(); + client.close(); + })); + + var cnt = 10; + req.on('data', function (data) { + cnt--; + if (cnt === 0) rs.destroy(); + }); + }); +} + +{ + var makeTransform = function () { + var tr = new Transform({ + transform: function (data, enc, cb) { + cb(null, data); + } + }); + + tr.on('close', common.mustCall()); + return tr; + }; + + var rs = new Readable({ + read: function () { + rs.push('hello'); + } + }); + + var _cnt = 10; + + var ws = new Writable({ + write: function (data, enc, cb) { + _cnt--; + if (_cnt === 0) return process.nextTick(cb, new Error('kaboom')); + cb(); + } + }); + + rs.on('close', common.mustCall()); + ws.on('close', common.mustCall()); + + pipeline(rs, makeTransform(), makeTransform(), makeTransform(), makeTransform(), makeTransform(), makeTransform(), ws, common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + })); +} + +{ + var oldStream = new Stream(); + + oldStream.pause = oldStream.resume = function () {}; + oldStream.write = function (data) { + oldStream.emit('data', data); + return true; + }; + oldStream.end = function () { + oldStream.emit('end'); + }; + + var _expected = [bufferShim.from('hello'), bufferShim.from('world')]; + + var _rs = new Readable({ + read: function () { + for (var _i = 0; _i < _expected.length; _i++) { + _rs.push(_expected[_i]); + } + _rs.push(null); + } + }); + + var _ws = new Writable({ + write: function (data, enc, cb) { + assert.deepStrictEqual(data, _expected.shift()); + cb(); + } + }); + + var _finished = false; + + _ws.on('finish', function () { + _finished = true; + }); + + pipeline(_rs, oldStream, _ws, common.mustCall(function (err) { + assert(!err, 'no error'); + assert(_finished, 'last stream finished'); + })); +} + +{ + var _oldStream = new Stream(); + + _oldStream.pause = _oldStream.resume = function () {}; + _oldStream.write = function (data) { + _oldStream.emit('data', data); + return true; + }; + _oldStream.end = function () { + _oldStream.emit('end'); + }; + + var destroyableOldStream = new Stream(); + + destroyableOldStream.pause = destroyableOldStream.resume = function () {}; + destroyableOldStream.destroy = common.mustCall(function () { + destroyableOldStream.emit('close'); + }); + destroyableOldStream.write = function (data) { + destroyableOldStream.emit('data', data); + return true; + }; + destroyableOldStream.end = function () { + destroyableOldStream.emit('end'); + }; + + var _rs2 = new Readable({ + read: function () { + _rs2.destroy(new Error('stop')); + } + }); + + var _ws2 = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + var _finished2 = false; + + _ws2.on('finish', function () { + _finished2 = true; + }); + + pipeline(_rs2, _oldStream, destroyableOldStream, _ws2, common.mustCall(function (err) { + assert.deepStrictEqual(err, new Error('stop')); + assert(!_finished2, 'should not finish'); + })); +} + +{ + var run = function () { + var _ref = _asyncToGenerator(function* () { + var read = new Readable({ + read: function () {} + }); + + var write = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + read.push('data'); + read.push(null); + + var finished = false; + + write.on('finish', function () { + finished = true; + }); + + yield pipelinePromise(read, write); + + assert(finished); + }); + + return function run() { + return _ref.apply(this, arguments); + }; + }(); + + var pipelinePromise = promisify(pipeline); + + run(); +} + +{ + var _read5 = new Readable({ + read: function () {} + }); + + var _transform = new Transform({ + transform: function (data, enc, cb) { + process.nextTick(cb, new Error('kaboom')); + } + }); + + var _write4 = new Writable({ + write: function (data, enc, cb) { + cb(); + } + }); + + _read5.on('close', common.mustCall()); + _transform.on('close', common.mustCall()); + _write4.on('close', common.mustCall()); + + process.on('uncaughtException', common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + })); + + var _dst2 = pipeline(_read5, _transform, _write4); + + assert.strictEqual(_dst2, _write4); + + _read5.push('hello'); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-push-order.js b/test/parallel/test-stream-push-order.js index 166d51d6b9..55b7f7d238 100644 --- a/test/parallel/test-stream-push-order.js +++ b/test/parallel/test-stream-push-order.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -49,6 +51,9 @@ s.read(0); // ACTUALLY [1, 3, 5, 6, 4, 2] process.on('exit', function () { - assert.deepStrictEqual(s._readableState.buffer.join(','), '1,2,3,4,5,6'); - console.log('ok'); + assert.deepStrictEqual(s.readableBuffer.join(','), '1,2,3,4,5,6'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-push-strings.js b/test/parallel/test-stream-push-strings.js index 00a6e8354c..60d4fd2e60 100644 --- a/test/parallel/test-stream-push-strings.js +++ b/test/parallel/test-stream-push-strings.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -82,5 +84,8 @@ var expect = ['first chunksecond to last chunk', 'last chunk']; process.on('exit', function () { assert.strictEqual(ms._chunks, -1); assert.deepStrictEqual(results, expect); - console.log('ok'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-async-iterators.js b/test/parallel/test-stream-readable-async-iterators.js new file mode 100644 index 0000000000..a3feea6aae --- /dev/null +++ b/test/parallel/test-stream-readable-async-iterators.js @@ -0,0 +1,495 @@ +'use strict'; + +var tests = function () { + var _ref = _asyncToGenerator(function* () { + yield _asyncToGenerator(function* () { + console.log('read without for..await'); + var max = 5; + var readable = new Readable({ + objectMode: true, + read: function () {} + }); + + var iter = readable[Symbol.asyncIterator](); + assert.strictEqual(iter.stream, readable); + var values = []; + for (var i = 0; i < max; i++) { + values.push(iter.next()); + } + Promise.all(values).then(common.mustCall(function (values) { + values.forEach(common.mustCall(function (item, i) { + return assert.strictEqual(item.value, 'hello-' + i); + }, 5)); + })); + + readable.push('hello-0'); + readable.push('hello-1'); + readable.push('hello-2'); + readable.push('hello-3'); + readable.push('hello-4'); + readable.push(null); + + var last = yield iter.next(); + assert.strictEqual(last.done, true); + })(); + + yield _asyncToGenerator(function* () { + console.log('read without for..await deferred'); + var readable = new Readable({ + objectMode: true, + read: function () {} + }); + + var iter = readable[Symbol.asyncIterator](); + assert.strictEqual(iter.stream, readable); + var values = []; + for (var i = 0; i < 3; i++) { + values.push(iter.next()); + } + + readable.push('hello-0'); + readable.push('hello-1'); + readable.push('hello-2'); + + var k = 0; + var results1 = yield Promise.all(values); + results1.forEach(common.mustCall(function (item) { + return assert.strictEqual(item.value, 'hello-' + k++); + }, 3)); + + values = []; + for (var _i = 0; _i < 2; _i++) { + values.push(iter.next()); + } + + readable.push('hello-3'); + readable.push('hello-4'); + readable.push(null); + + var results2 = yield Promise.all(values); + results2.forEach(common.mustCall(function (item) { + return assert.strictEqual(item.value, 'hello-' + k++); + }, 2)); + + var last = yield iter.next(); + assert.strictEqual(last.done, true); + })(); + + yield _asyncToGenerator(function* () { + console.log('read without for..await with errors'); + var max = 3; + var readable = new Readable({ + objectMode: true, + read: function () {} + }); + + var iter = readable[Symbol.asyncIterator](); + assert.strictEqual(iter.stream, readable); + var values = []; + var errors = []; + var i = void 0; + for (i = 0; i < max; i++) { + values.push(iter.next()); + } + for (i = 0; i < 2; i++) { + errors.push(iter.next()); + } + + readable.push('hello-0'); + readable.push('hello-1'); + readable.push('hello-2'); + + var resolved = yield Promise.all(values); + + resolved.forEach(common.mustCall(function (item, i) { + return assert.strictEqual(item.value, 'hello-' + i); + }, max)); + + errors.forEach(function (promise) { + promise.catch(common.mustCall(function (err) { + assert.strictEqual(err.message, 'kaboom'); + })); + }); + + readable.destroy(new Error('kaboom')); + })(); + + yield _asyncToGenerator(function* () { + console.log('call next() after error'); + var readable = new Readable({ + read: function () {} + }); + var iterator = readable[Symbol.asyncIterator](); + + var err = new Error('kaboom'); + readable.destroy(new Error('kaboom')); + yield function (f, e) { + var success = false;f().then(function () { + success = true;throw new Error('should not succeeed'); + }).catch(function (e2) { + if (success) { + throw e2; + }assert.strictEqual(e.message, e2.message); + }); + }(iterator.next.bind(iterator), err); + })(); + + yield _asyncToGenerator(function* () { + console.log('read object mode'); + var max = 42; + var readed = 0; + var received = 0; + var readable = new Readable({ + objectMode: true, + read: function () { + this.push('hello'); + if (++readed === max) { + this.push(null); + } + } + }); + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = _asyncIterator(readable), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) { + var k = _value; + + received++; + assert.strictEqual(k, 'hello'); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + yield _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + assert.strictEqual(readed, received); + })(); + + yield _asyncToGenerator(function* () { + console.log('destroy sync'); + var readable = new Readable({ + objectMode: true, + read: function () { + this.destroy(new Error('kaboom from read')); + } + }); + + var err = void 0; + try { + // eslint-disable-next-line no-unused-vars + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = _asyncIterator(readable), _step2, _value2; _step2 = yield _iterator2.next(), _iteratorNormalCompletion2 = _step2.done, _value2 = yield _step2.value, !_iteratorNormalCompletion2; _iteratorNormalCompletion2 = true) { + var k = _value2; + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + yield _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + } catch (e) { + err = e; + } + assert.strictEqual(err.message, 'kaboom from read'); + })(); + + yield _asyncToGenerator(function* () { + console.log('destroy async'); + var readable = new Readable({ + objectMode: true, + read: function () { + var _this = this; + + if (!this.pushed) { + this.push('hello'); + this.pushed = true; + + setImmediate(function () { + _this.destroy(new Error('kaboom')); + }); + } + } + }); + + var received = 0; + + var err = null; + try { + // eslint-disable-next-line no-unused-vars + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = _asyncIterator(readable), _step3, _value3; _step3 = yield _iterator3.next(), _iteratorNormalCompletion3 = _step3.done, _value3 = yield _step3.value, !_iteratorNormalCompletion3; _iteratorNormalCompletion3 = true) { + var k = _value3; + + received++; + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + yield _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + } catch (e) { + err = e; + } + + assert.strictEqual(err.message, 'kaboom'); + assert.strictEqual(received, 1); + })(); + + yield _asyncToGenerator(function* () { + console.log('destroyed by throw'); + var readable = new Readable({ + objectMode: true, + read: function () { + this.push('hello'); + } + }); + + var err = null; + try { + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = _asyncIterator(readable), _step4, _value4; _step4 = yield _iterator4.next(), _iteratorNormalCompletion4 = _step4.done, _value4 = yield _step4.value, !_iteratorNormalCompletion4; _iteratorNormalCompletion4 = true) { + var k = _value4; + + assert.strictEqual(k, 'hello'); + throw new Error('kaboom'); + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4.return) { + yield _iterator4.return(); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + } catch (e) { + err = e; + } + + assert.strictEqual(err.message, 'kaboom'); + assert.strictEqual(readable.destroyed, true); + })(); + + yield _asyncToGenerator(function* () { + console.log('destroyed sync after push'); + var readable = new Readable({ + objectMode: true, + read: function () { + this.push('hello'); + this.destroy(new Error('kaboom')); + } + }); + + var received = 0; + + var err = null; + try { + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = _asyncIterator(readable), _step5, _value5; _step5 = yield _iterator5.next(), _iteratorNormalCompletion5 = _step5.done, _value5 = yield _step5.value, !_iteratorNormalCompletion5; _iteratorNormalCompletion5 = true) { + var k = _value5; + + assert.strictEqual(k, 'hello'); + received++; + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5.return) { + yield _iterator5.return(); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + } catch (e) { + err = e; + } + + assert.strictEqual(err.message, 'kaboom'); + assert.strictEqual(received, 1); + })(); + + yield _asyncToGenerator(function* () { + console.log('push async'); + var max = 42; + var readed = 0; + var received = 0; + var readable = new Readable({ + objectMode: true, + read: function () { + var _this2 = this; + + setImmediate(function () { + _this2.push('hello'); + if (++readed === max) { + _this2.push(null); + } + }); + } + }); + + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = _asyncIterator(readable), _step6, _value6; _step6 = yield _iterator6.next(), _iteratorNormalCompletion6 = _step6.done, _value6 = yield _step6.value, !_iteratorNormalCompletion6; _iteratorNormalCompletion6 = true) { + var k = _value6; + + received++; + assert.strictEqual(k, 'hello'); + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6.return) { + yield _iterator6.return(); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + assert.strictEqual(readed, received); + })(); + + yield _asyncToGenerator(function* () { + console.log('push binary async'); + var max = 42; + var readed = 0; + var readable = new Readable({ + read: function () { + var _this3 = this; + + setImmediate(function () { + _this3.push('hello'); + if (++readed === max) { + _this3.push(null); + } + }); + } + }); + + var expected = ''; + readable.setEncoding('utf8'); + readable.pause(); + readable.on('data', function (chunk) { + expected += chunk; + }); + + var data = ''; + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = _asyncIterator(readable), _step7, _value7; _step7 = yield _iterator7.next(), _iteratorNormalCompletion7 = _step7.done, _value7 = yield _step7.value, !_iteratorNormalCompletion7; _iteratorNormalCompletion7 = true) { + var k = _value7; + + data += k; + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7.return) { + yield _iterator7.return(); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } + + assert.strictEqual(data, expected); + })(); + }); + + return function tests() { + return _ref.apply(this, arguments); + }; +}(); + +// to avoid missing some tests if a promise does not resolve + + +function _asyncIterator(iterable) { if (typeof Symbol === "function") { if (Symbol.asyncIterator) { var method = iterable[Symbol.asyncIterator]; if (method != null) return method.call(iterable); } if (Symbol.iterator) { return iterable[Symbol.iterator](); } } throw new TypeError("Object is not async iterable"); } + +function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); + +var _require = require('../../'), + Readable = _require.Readable; + +var assert = require('assert/'); + +tests().then(common.mustCall()); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-constructor-set-methods.js b/test/parallel/test-stream-readable-constructor-set-methods.js index 7974f9c290..15302105d0 100644 --- a/test/parallel/test-stream-readable-constructor-set-methods.js +++ b/test/parallel/test-stream-readable-constructor-set-methods.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -10,4 +12,7 @@ var _read = common.mustCall(function _read(n) { }); var r = new Readable({ read: _read }); -r.resume(); \ No newline at end of file +r.resume(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-destroy.js b/test/parallel/test-stream-readable-destroy.js index 3df1e2a180..e5a73d36dd 100644 --- a/test/parallel/test-stream-readable-destroy.js +++ b/test/parallel/test-stream-readable-destroy.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -18,7 +20,7 @@ var _require2 = require('util'), }); read.resume(); - read.on('end', common.mustCall()); + read.on('close', common.mustCall()); read.destroy(); assert.strictEqual(read.destroyed, true); @@ -32,7 +34,8 @@ var _require2 = require('util'), var expected = new Error('kaboom'); - _read.on('end', common.mustCall()); + _read.on('end', common.mustNotCall('no end event')); + _read.on('close', common.mustCall()); _read.on('error', common.mustCall(function (err) { assert.strictEqual(err, expected); })); @@ -54,6 +57,7 @@ var _require2 = require('util'), var _expected = new Error('kaboom'); _read2.on('end', common.mustNotCall('no end event')); + _read2.on('close', common.mustCall()); _read2.on('error', common.mustCall(function (err) { assert.strictEqual(err, _expected); })); @@ -78,6 +82,7 @@ var _require2 = require('util'), // error is swallowed by the custom _destroy _read3.on('error', common.mustNotCall('no error event')); + _read3.on('close', common.mustCall()); _read3.destroy(_expected2); assert.strictEqual(_read3.destroyed, true); @@ -116,6 +121,7 @@ var _require2 = require('util'), var fail = common.mustNotCall('no end event'); _read5.on('end', fail); + _read5.on('close', common.mustCall()); _read5.destroy(); @@ -180,7 +186,21 @@ var _require2 = require('util'), var _expected4 = new Error('kaboom'); + _read8.on('close', common.mustCall()); _read8.destroy(_expected4, common.mustCall(function (err) { assert.strictEqual(_expected4, err); })); -} \ No newline at end of file +} + +{ + var _read9 = new Readable({ + read: function () {} + }); + + _read9.destroy(); + _read9.push('hi'); + _read9.on('data', common.mustNotCall()); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-emittedReadable.js b/test/parallel/test-stream-readable-emittedReadable.js index 13695547f7..4812dcb4ab 100644 --- a/test/parallel/test-stream-readable-emittedReadable.js +++ b/test/parallel/test-stream-readable-emittedReadable.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -12,30 +14,33 @@ var readable = new Readable({ // Initialized to false. assert.strictEqual(readable._readableState.emittedReadable, false); +var expected = [bufferShim.from('foobar'), bufferShim.from('quo'), null]; readable.on('readable', common.mustCall(function () { // emittedReadable should be true when the readable event is emitted assert.strictEqual(readable._readableState.emittedReadable, true); - readable.read(); + assert.deepStrictEqual(readable.read(), expected.shift()); // emittedReadable is reset to false during read() assert.strictEqual(readable._readableState.emittedReadable, false); -}, 4)); +}, 3)); // When the first readable listener is just attached, // emittedReadable should be false assert.strictEqual(readable._readableState.emittedReadable, false); -// Each one of these should trigger a readable event. +// These trigger a single 'readable', as things are batched up process.nextTick(common.mustCall(function () { readable.push('foo'); })); process.nextTick(common.mustCall(function () { readable.push('bar'); })); -process.nextTick(common.mustCall(function () { + +// these triggers two readable events +setImmediate(common.mustCall(function () { readable.push('quo'); -})); -process.nextTick(common.mustCall(function () { - readable.push(null); + process.nextTick(common.mustCall(function () { + readable.push(null); + })); })); var noRead = new Readable({ @@ -69,4 +74,7 @@ flowing.push('bar'); flowing.push('quo'); process.nextTick(common.mustCall(function () { flowing.push(null); -})); \ No newline at end of file +})); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-event.js b/test/parallel/test-stream-readable-event.js index 587f1acbef..62f39ef40f 100644 --- a/test/parallel/test-stream-readable-event.js +++ b/test/parallel/test-stream-readable-event.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -84,4 +86,54 @@ var Readable = require('../../').Readable; assert(!_r2._readableState.reading); _r2.on('readable', common.mustCall()); }, 1); -} \ No newline at end of file +} + +{ + // pushing a empty string in non-objectMode should + // trigger next `read()`. + var underlyingData = ['', 'x', 'y', '', 'z']; + var expected = underlyingData.filter(function (data) { + return data; + }); + var result = []; + + var _r3 = new Readable({ + encoding: 'utf8' + }); + _r3._read = function () { + var _this = this; + + process.nextTick(function () { + if (!underlyingData.length) { + _this.push(null); + } else { + _this.push(underlyingData.shift()); + } + }); + }; + + _r3.on('readable', function () { + var data = _r3.read(); + if (data !== null) result.push(data); + }); + + _r3.on('end', common.mustCall(function () { + assert.deepStrictEqual(result, expected); + })); +} + +{ + // #20923 + var _r4 = new Readable(); + _r4._read = function () { + // actually doing thing here + }; + _r4.on('data', function () {}); + + _r4.removeAllListeners(); + + assert.strictEqual(_r4.eventNames().length, 0); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-flow-recursion.js b/test/parallel/test-stream-readable-flow-recursion.js index 0b6704a212..1e81189c16 100644 --- a/test/parallel/test-stream-readable-flow-recursion.js +++ b/test/parallel/test-stream-readable-flow-recursion.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -66,8 +68,11 @@ process.on('exit', function (code) { // we pushed up the high water mark assert.strictEqual(stream.readableHighWaterMark, 8192); // length is 0 right now, because we pulled it all out. - assert.strictEqual(stream._readableState.length, 0); + assert.strictEqual(stream.readableLength, 0); assert(!code); assert.strictEqual(depth, 0); - console.log('ok'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-invalid-chunk.js b/test/parallel/test-stream-readable-invalid-chunk.js index 81f0eed852..c756875a8e 100644 --- a/test/parallel/test-stream-readable-invalid-chunk.js +++ b/test/parallel/test-stream-readable-invalid-chunk.js @@ -1,22 +1,32 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); +var common = require('../common'); var stream = require('../../'); -var assert = require('assert/'); var readable = new stream.Readable({ read: function () {} }); -var errMessage = /Invalid non-string\/buffer chunk/; -assert.throws(function () { +function checkError(fn) { + common.expectsError(fn, { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError + }); +} + +checkError(function () { return readable.push([]); -}, errMessage); -assert.throws(function () { +}); +checkError(function () { return readable.push({}); -}, errMessage); -assert.throws(function () { +}); +checkError(function () { return readable.push(0); -}, errMessage); \ No newline at end of file +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-needReadable.js b/test/parallel/test-stream-readable-needReadable.js index b7e1d5ec7f..fa1a793b6f 100644 --- a/test/parallel/test-stream-readable-needReadable.js +++ b/test/parallel/test-stream-readable-needReadable.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -40,7 +42,7 @@ asyncReadable.on('readable', common.mustCall(function () { // then we need to notify the reader on future changes. assert.strictEqual(asyncReadable._readableState.needReadable, true); } -}, 3)); +}, 2)); process.nextTick(common.mustCall(function () { asyncReadable.push('foooo'); @@ -48,8 +50,9 @@ process.nextTick(common.mustCall(function () { process.nextTick(common.mustCall(function () { asyncReadable.push('bar'); })); -process.nextTick(common.mustCall(function () { +setImmediate(common.mustCall(function () { asyncReadable.push(null); + assert.strictEqual(asyncReadable._readableState.needReadable, false); })); var flowing = new Readable({ @@ -86,13 +89,16 @@ slowProducer.on('readable', common.mustCall(function () { process.nextTick(common.mustCall(function () { slowProducer.push('foo'); + process.nextTick(common.mustCall(function () { + slowProducer.push('foo'); + process.nextTick(common.mustCall(function () { + slowProducer.push('foo'); + process.nextTick(common.mustCall(function () { + slowProducer.push(null); + })); + })); + })); })); -process.nextTick(common.mustCall(function () { - slowProducer.push('foo'); -})); -process.nextTick(common.mustCall(function () { - slowProducer.push('foo'); -})); -process.nextTick(common.mustCall(function () { - slowProducer.push(null); -})); \ No newline at end of file +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-no-unneeded-readable.js b/test/parallel/test-stream-readable-no-unneeded-readable.js new file mode 100644 index 0000000000..d7d9b1ed1a --- /dev/null +++ b/test/parallel/test-stream-readable-no-unneeded-readable.js @@ -0,0 +1,74 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ +var common = require('../common'); + +var _require = require('../../'), + Readable = _require.Readable, + PassThrough = _require.PassThrough; + +function test(r) { + var wrapper = new Readable({ + read: function () { + var data = r.read(); + + if (data) { + wrapper.push(data); + return; + } + + r.once('readable', function () { + data = r.read(); + if (data) { + wrapper.push(data); + } + // else the end event should fire + }); + } + }); + + r.once('end', function () { + wrapper.push(null); + }); + + wrapper.resume(); + wrapper.once('end', common.mustCall()); +} + +{ + var source = new Readable({ + read: function () {} + }); + source.push('foo'); + source.push('bar'); + source.push(null); + + var pt = source.pipe(new PassThrough()); + test(pt); +} + +{ + // This is the underlying cause of the above test case. + var pushChunks = ['foo', 'bar']; + var r = new Readable({ + read: function () { + var chunk = pushChunks.shift(); + if (chunk) { + // synchronous call + r.push(chunk); + } else { + // asynchronous call + process.nextTick(function () { + return r.push(null); + }); + } + } + }); + + test(r); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-object-multi-push-async.js b/test/parallel/test-stream-readable-object-multi-push-async.js new file mode 100644 index 0000000000..4c987c069a --- /dev/null +++ b/test/parallel/test-stream-readable-object-multi-push-async.js @@ -0,0 +1,204 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var common = require('../common'); +var assert = require('assert/'); + +var _require = require('../../'), + Readable = _require.Readable; + +var MAX = 42; +var BATCH = 10; + +{ + var readable = new Readable({ + objectMode: true, + read: common.mustCall(function () { + var _this = this; + + console.log('>> READ'); + fetchData(function (err, data) { + if (err) { + _this.destroy(err); + return; + } + + if (data.length === 0) { + console.log('pushing null'); + _this.push(null); + return; + } + + console.log('pushing'); + data.forEach(function (d) { + return _this.push(d); + }); + }); + }, Math.floor(MAX / BATCH) + 2) + }); + + var i = 0; + function fetchData(cb) { + if (i > MAX) { + setTimeout(cb, 10, null, []); + } else { + var array = []; + var max = i + BATCH; + for (; i < max; i++) { + array.push(i); + } + setTimeout(cb, 10, null, array); + } + } + + readable.on('readable', function () { + var data = void 0; + console.log('readable emitted'); + while (data = readable.read()) { + console.log(data); + } + }); + + readable.on('end', common.mustCall(function () { + assert.strictEqual(i, (Math.floor(MAX / BATCH) + 1) * BATCH); + })); +} + +{ + var _readable = new Readable({ + objectMode: true, + read: common.mustCall(function () { + var _this2 = this; + + console.log('>> READ'); + fetchData(function (err, data) { + if (err) { + _this2.destroy(err); + return; + } + + if (data.length === 0) { + console.log('pushing null'); + _this2.push(null); + return; + } + + console.log('pushing'); + data.forEach(function (d) { + return _this2.push(d); + }); + }); + }, Math.floor(MAX / BATCH) + 2) + }); + + var _i = 0; + function fetchData(cb) { + if (_i > MAX) { + setTimeout(cb, 10, null, []); + } else { + var array = []; + var max = _i + BATCH; + for (; _i < max; _i++) { + array.push(_i); + } + setTimeout(cb, 10, null, array); + } + } + + _readable.on('data', function (data) { + console.log('data emitted', data); + }); + + _readable.on('end', common.mustCall(function () { + assert.strictEqual(_i, (Math.floor(MAX / BATCH) + 1) * BATCH); + })); +} + +{ + var _readable2 = new Readable({ + objectMode: true, + read: common.mustCall(function () { + var _this3 = this; + + console.log('>> READ'); + fetchData(function (err, data) { + if (err) { + _this3.destroy(err); + return; + } + + console.log('pushing'); + data.forEach(function (d) { + return _this3.push(d); + }); + + if (data[BATCH - 1] >= MAX) { + console.log('pushing null'); + _this3.push(null); + } + }); + }, Math.floor(MAX / BATCH) + 1) + }); + + var _i2 = 0; + function fetchData(cb) { + var array = []; + var max = _i2 + BATCH; + for (; _i2 < max; _i2++) { + array.push(_i2); + } + setTimeout(cb, 10, null, array); + } + + _readable2.on('data', function (data) { + console.log('data emitted', data); + }); + + _readable2.on('end', common.mustCall(function () { + assert.strictEqual(_i2, (Math.floor(MAX / BATCH) + 1) * BATCH); + })); +} + +{ + var _readable3 = new Readable({ + objectMode: true, + read: common.mustNotCall() + }); + + _readable3.on('data', common.mustNotCall()); + + _readable3.push(null); + + var nextTickPassed = false; + process.nextTick(function () { + nextTickPassed = true; + }); + + _readable3.on('end', common.mustCall(function () { + assert.strictEqual(nextTickPassed, true); + })); +} + +{ + var _readable4 = new Readable({ + objectMode: true, + read: common.mustCall() + }); + + _readable4.on('data', function (data) { + console.log('data emitted', data); + }); + + _readable4.on('end', common.mustCall()); + + setImmediate(function () { + _readable4.push('aaa'); + _readable4.push(null); + }); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-pause-and-resume.js b/test/parallel/test-stream-readable-pause-and-resume.js new file mode 100644 index 0000000000..b43d8bb6c4 --- /dev/null +++ b/test/parallel/test-stream-readable-pause-and-resume.js @@ -0,0 +1,49 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +var _require = require('../../'), + Readable = _require.Readable; + +var common = require('../common'); + +var ticks = 18; +var expectedData = 19; + +var rs = new Readable({ + objectMode: true, + read: function () { + if (ticks-- > 0) return process.nextTick(function () { + return rs.push({}); + }); + rs.push({}); + rs.push(null); + } +}); + +rs.on('end', common.mustCall()); +readAndPause(); + +function readAndPause() { + // Does a on(data) -> pause -> wait -> resume -> on(data) ... loop. + // Expects on(data) to never fire if the stream is paused. + var ondata = common.mustCall(function (data) { + rs.pause(); + + expectedData--; + if (expectedData <= 0) return; + + setImmediate(function () { + rs.removeListener('data', ondata); + readAndPause(); + rs.resume(); + }); + }, 1); // only call ondata once + + rs.on('data', ondata); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-reading-readingMore.js b/test/parallel/test-stream-readable-reading-readingMore.js index 8512dcf7ee..5d383247bb 100644 --- a/test/parallel/test-stream-readable-reading-readingMore.js +++ b/test/parallel/test-stream-readable-reading-readingMore.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -5,62 +7,167 @@ var common = require('../common'); var assert = require('assert/'); var Readable = require('../../').Readable; -var readable = new Readable({ - read: function (size) {} -}); +{ + var readable = new Readable({ + read: function (size) {} + }); -var state = readable._readableState; + var state = readable._readableState; -// Starting off with false initially. -assert.strictEqual(state.reading, false); -assert.strictEqual(state.readingMore, false); + // Starting off with false initially. + assert.strictEqual(state.reading, false); + assert.strictEqual(state.readingMore, false); -readable.on('data', common.mustCall(function (data) { - // while in a flowing state, should try to read more. - if (state.flowing) assert.strictEqual(state.readingMore, true); + readable.on('data', common.mustCall(function (data) { + // while in a flowing state with a 'readable' listener + // we should not be reading more + if (readable.readableFlowing) assert.strictEqual(state.readingMore, true); - // reading as long as we've not ended - assert.strictEqual(state.reading, !state.ended); -}, 2)); + // reading as long as we've not ended + assert.strictEqual(state.reading, !state.ended); + }, 2)); -function onStreamEnd() { - // End of stream; state.reading is false - // And so should be readingMore. - assert.strictEqual(state.readingMore, false); - assert.strictEqual(state.reading, false); -} + function onStreamEnd() { + // End of stream; state.reading is false + // And so should be readingMore. + assert.strictEqual(state.readingMore, false); + assert.strictEqual(state.reading, false); + } + + readable.on('readable', common.mustCall(function () { + // 'readable' always gets called before 'end' + // since 'end' hasn't been emitted, more data could be incoming + assert.strictEqual(state.readingMore, true); + + // if the stream has ended, we shouldn't be reading + assert.strictEqual(state.ended, !state.reading); + + var data = readable.read(); + if (data === null) // reached end of stream + process.nextTick(common.mustCall(onStreamEnd, 1)); + }, 2)); -readable.on('readable', common.mustCall(function () { - // 'readable' always gets called before 'end' - // since 'end' hasn't been emitted, more data could be incoming + readable.on('end', common.mustCall(onStreamEnd)); + readable.push('pushed'); + + readable.read(6); + + // reading + assert.strictEqual(state.reading, true); assert.strictEqual(state.readingMore, true); - // if the stream has ended, we shouldn't be reading - assert.strictEqual(state.ended, !state.reading); + // add chunk to front + readable.unshift('unshifted'); + + // end + readable.push(null); +} + +{ + var _readable = new Readable({ + read: function (size) {} + }); + + var _state = _readable._readableState; + + // Starting off with false initially. + assert.strictEqual(_state.reading, false); + assert.strictEqual(_state.readingMore, false); + + _readable.on('data', common.mustCall(function (data) { + // while in a flowing state without a 'readable' listener + // we should be reading more + if (_readable.readableFlowing) assert.strictEqual(_state.readingMore, true); - if (readable.read() === null) // reached end of stream - process.nextTick(common.mustCall(onStreamEnd, 1)); -}, 2)); + // reading as long as we've not ended + assert.strictEqual(_state.reading, !_state.ended); + }, 2)); -readable.on('end', common.mustCall(onStreamEnd)); + function onStreamEnd() { + // End of stream; state.reading is false + // And so should be readingMore. + assert.strictEqual(_state.readingMore, false); + assert.strictEqual(_state.reading, false); + } -readable.push('pushed'); + _readable.on('end', common.mustCall(onStreamEnd)); + _readable.push('pushed'); -// stop emitting 'data' events -readable.pause(); + // stop emitting 'data' events + assert.strictEqual(_state.flowing, true); + _readable.pause(); -// read() should only be called while operating in paused mode -readable.read(6); + // paused + assert.strictEqual(_state.reading, false); + assert.strictEqual(_state.flowing, false); -// reading -assert.strictEqual(state.reading, true); -assert.strictEqual(state.readingMore, true); + _readable.resume(); + assert.strictEqual(_state.reading, false); + assert.strictEqual(_state.flowing, true); -// resume emitting 'data' events -readable.resume(); + // add chunk to front + _readable.unshift('unshifted'); -// add chunk to front -readable.unshift('unshifted'); + // end + _readable.push(null); +} + +{ + var _readable2 = new Readable({ + read: function (size) {} + }); + + var _state2 = _readable2._readableState; + + // Starting off with false initially. + assert.strictEqual(_state2.reading, false); + assert.strictEqual(_state2.readingMore, false); + + var onReadable = common.mustNotCall; + + _readable2.on('readable', onReadable); + + _readable2.on('data', common.mustCall(function (data) { + // reading as long as we've not ended + assert.strictEqual(_state2.reading, !_state2.ended); + }, 2)); + + _readable2.removeListener('readable', onReadable); + + function onStreamEnd() { + // End of stream; state.reading is false + // And so should be readingMore. + assert.strictEqual(_state2.readingMore, false); + assert.strictEqual(_state2.reading, false); + } -// end -readable.push(null); \ No newline at end of file + _readable2.on('end', common.mustCall(onStreamEnd)); + _readable2.push('pushed'); + + // we are still not flowing, we will be resuming in the next tick + assert.strictEqual(_state2.flowing, false); + + // wait for nextTick, so the readableListener flag resets + process.nextTick(function () { + _readable2.resume(); + + // stop emitting 'data' events + assert.strictEqual(_state2.flowing, true); + _readable2.pause(); + + // paused + assert.strictEqual(_state2.flowing, false); + + _readable2.resume(); + assert.strictEqual(_state2.flowing, true); + + // add chunk to front + _readable2.unshift('unshifted'); + + // end + _readable2.push(null); + }); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-resumeScheduled.js b/test/parallel/test-stream-readable-resumeScheduled.js index c32fb35df8..c3e6cc7219 100644 --- a/test/parallel/test-stream-readable-resumeScheduled.js +++ b/test/parallel/test-stream-readable-resumeScheduled.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -73,4 +75,7 @@ var _require = require('../../'), process.nextTick(common.mustCall(function () { assert.strictEqual(_r2._readableState.resumeScheduled, false); })); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-setEncoding-null.js b/test/parallel/test-stream-readable-setEncoding-null.js new file mode 100644 index 0000000000..4c3b1d91d9 --- /dev/null +++ b/test/parallel/test-stream-readable-setEncoding-null.js @@ -0,0 +1,23 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ + +require('../common'); +var assert = require('assert/'); + +var _require = require('../../'), + Readable = _require.Readable; + +{ + var readable = new Readable({ encoding: 'hex' }); + assert.strictEqual(readable._readableState.encoding, 'hex'); + + readable.setEncoding(null); + + assert.strictEqual(readable._readableState.encoding, 'utf8'); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readable-with-unimplemented-_read.js b/test/parallel/test-stream-readable-with-unimplemented-_read.js index 92bfbc030a..19a588ab79 100644 --- a/test/parallel/test-stream-readable-with-unimplemented-_read.js +++ b/test/parallel/test-stream-readable-with-unimplemented-_read.js @@ -1,12 +1,22 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); -var stream = require('../../'); -var assert = require('assert/'); +var common = require('../common'); + +var _require = require('../../'), + Readable = _require.Readable; + +var readable = new Readable(); -var readable = new stream.Readable(); +readable.on('error', common.expectsError({ + code: 'ERR_METHOD_NOT_IMPLEMENTED', + type: Error, + message: 'The _read() method is not implemented' +})); -assert.throws(function () { - return readable.read(); -}, /not implemented/); \ No newline at end of file +readable.read(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-readableListening-state.js b/test/parallel/test-stream-readableListening-state.js index 08e552145f..91fa25358b 100644 --- a/test/parallel/test-stream-readableListening-state.js +++ b/test/parallel/test-stream-readableListening-state.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -33,4 +35,7 @@ r2.on('data', common.mustCall(function (chunk) { assert.strictEqual(r2._readableState.readableListening, false); })); -r2.push(bufferShim.from('Testing readableListening state')); \ No newline at end of file +r2.push(bufferShim.from('Testing readableListening state')); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-callback-twice.js b/test/parallel/test-stream-transform-callback-twice.js index cd8cdc668c..4ae1f61630 100644 --- a/test/parallel/test-stream-transform-callback-twice.js +++ b/test/parallel/test-stream-transform-callback-twice.js @@ -1,8 +1,9 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ var common = require('../common'); -var assert = require('assert/'); var _require = require('../../'), Transform = _require.Transform; @@ -13,8 +14,13 @@ var stream = new Transform({ } }); -stream.on('error', common.mustCall(function (err) { - assert.strictEqual(err.toString(), 'Error: write callback called multiple times'); +stream.on('error', common.expectsError({ + type: Error, + message: 'Callback called multiple times', + code: 'ERR_MULTIPLE_CALLBACK' })); -stream.write('foo'); \ No newline at end of file +stream.write('foo'); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-constructor-set-methods.js b/test/parallel/test-stream-transform-constructor-set-methods.js index ed4858b3cd..1944f3606b 100644 --- a/test/parallel/test-stream-transform-constructor-set-methods.js +++ b/test/parallel/test-stream-transform-constructor-set-methods.js @@ -1,40 +1,50 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ var common = require('../common'); -var assert = require('assert/'); -var Transform = require('../../').Transform; +var _require = require('assert/'), + strictEqual = _require.strictEqual; + +var _require2 = require('../../'), + Transform = _require2.Transform; + +var t = new Transform(); -var _transform = common.mustCall(function _transform(d, e, n) { - n(); +t.on('error', common.expectsError({ + type: Error, + code: 'ERR_METHOD_NOT_IMPLEMENTED', + message: 'The _transform() method is not implemented' +})); + +t.end(bufferShim.from('blerg')); + +var _transform = common.mustCall(function (chunk, _, next) { + next(); }); -var _final = common.mustCall(function _final(n) { - n(); +var _final = common.mustCall(function (next) { + next(); }); -var _flush = common.mustCall(function _flush(n) { - n(); +var _flush = common.mustCall(function (next) { + next(); }); -var t = new Transform({ +var t2 = new Transform({ transform: _transform, flush: _flush, final: _final }); -var t2 = new Transform({}); - -t.end(bufferShim.from('blerg')); -t.resume(); - -assert.throws(function () { - t2.end(bufferShim.from('blerg')); -}, /^Error: .*[Nn]ot implemented$/); +strictEqual(t2._transform, _transform); +strictEqual(t2._flush, _flush); +strictEqual(t2._final, _final); -process.on('exit', function () { - assert.strictEqual(t._transform, _transform); - assert.strictEqual(t._flush, _flush); - assert.strictEqual(t._final, _final); +t2.end(bufferShim.from('blerg')); +t2.resume(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-destroy.js b/test/parallel/test-stream-transform-destroy.js index 1d30d6f512..670c567fea 100644 --- a/test/parallel/test-stream-transform-destroy.js +++ b/test/parallel/test-stream-transform-destroy.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -16,9 +18,9 @@ var assert = require('assert/'); transform.resume(); - transform.on('end', common.mustCall()); + transform.on('end', common.mustNotCall()); transform.on('close', common.mustCall()); - transform.on('finish', common.mustCall()); + transform.on('finish', common.mustNotCall()); transform.destroy(); } @@ -31,8 +33,8 @@ var assert = require('assert/'); var expected = new Error('kaboom'); - _transform.on('end', common.mustCall()); - _transform.on('finish', common.mustCall()); + _transform.on('end', common.mustNotCall()); + _transform.on('finish', common.mustNotCall()); _transform.on('close', common.mustCall()); _transform.on('error', common.mustCall(function (err) { assert.strictEqual(err, expected); @@ -54,7 +56,7 @@ var assert = require('assert/'); var _expected = new Error('kaboom'); _transform2.on('finish', common.mustNotCall('no finish event')); - _transform2.on('close', common.mustNotCall('no close event')); + _transform2.on('close', common.mustCall()); _transform2.on('error', common.mustCall(function (err) { assert.strictEqual(err, _expected); })); @@ -75,7 +77,7 @@ var assert = require('assert/'); _transform3.resume(); _transform3.on('end', common.mustNotCall('no end event')); - _transform3.on('close', common.mustNotCall('no close event')); + _transform3.on('close', common.mustCall()); _transform3.on('finish', common.mustNotCall('no finish event')); // error is swallowed by the custom _destroy @@ -118,7 +120,7 @@ var assert = require('assert/'); _transform5.on('finish', fail); _transform5.on('end', fail); - _transform5.on('close', fail); + _transform5.on('close', common.mustCall()); _transform5.destroy(); @@ -140,7 +142,7 @@ var assert = require('assert/'); cb(_expected3); }, 1); - _transform6.on('close', common.mustNotCall('no close event')); + _transform6.on('close', common.mustCall()); _transform6.on('finish', common.mustNotCall('no finish event')); _transform6.on('end', common.mustNotCall('no end event')); _transform6.on('error', common.mustCall(function (err) { @@ -148,4 +150,7 @@ var assert = require('assert/'); })); _transform6.destroy(); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-final-sync.js b/test/parallel/test-stream-transform-final-sync.js index 8667612bca..7fbf906bcc 100644 --- a/test/parallel/test-stream-transform-final-sync.js +++ b/test/parallel/test-stream-transform-final-sync.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -9,7 +11,7 @@ var state = 0; /* What you do -var stream = new tream.Transform({ +var stream = new stream.Transform({ transform: function transformCallback(chunk, _, next) { // part 1 this.push(chunk); @@ -61,42 +63,55 @@ The order things are called var t = new stream.Transform({ objectMode: true, transform: common.mustCall(function (chunk, _, next) { - assert.strictEqual(++state, chunk, 'transformCallback part 1'); + // transformCallback part 1 + assert.strictEqual(++state, chunk); this.push(state); - assert.strictEqual(++state, chunk + 2, 'transformCallback part 2'); + // transformCallback part 2 + assert.strictEqual(++state, chunk + 2); process.nextTick(next); }, 3), final: common.mustCall(function (done) { state++; - assert.strictEqual(state, 10, 'finalCallback part 1'); + // finalCallback part 1 + assert.strictEqual(state, 10); state++; - assert.strictEqual(state, 11, 'finalCallback part 2'); + // finalCallback part 2 + assert.strictEqual(state, 11); done(); }, 1), flush: common.mustCall(function (done) { state++; - assert.strictEqual(state, 12, 'flushCallback part 1'); + // fluchCallback part 1 + assert.strictEqual(state, 12); process.nextTick(function () { state++; - assert.strictEqual(state, 15, 'flushCallback part 2'); + // fluchCallback part 2 + assert.strictEqual(state, 15); done(); }); }, 1) }); t.on('finish', common.mustCall(function () { state++; - assert.strictEqual(state, 13, 'finishListener'); + // finishListener + assert.strictEqual(state, 13); }, 1)); t.on('end', common.mustCall(function () { state++; - assert.strictEqual(state, 16, 'end event'); + // endEvent + assert.strictEqual(state, 16); }, 1)); t.on('data', common.mustCall(function (d) { - assert.strictEqual(++state, d + 1, 'dataListener'); + // dataListener + assert.strictEqual(++state, d + 1); }, 3)); t.write(1); t.write(4); t.end(7, common.mustCall(function () { state++; - assert.strictEqual(state, 14, 'endMethodCallback'); -}, 1)); \ No newline at end of file + // endMethodCallback + assert.strictEqual(state, 14); +}, 1)); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-final.js b/test/parallel/test-stream-transform-final.js index 50e0ce8a1d..bdd2f05faa 100644 --- a/test/parallel/test-stream-transform-final.js +++ b/test/parallel/test-stream-transform-final.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -9,7 +11,7 @@ var state = 0; /* What you do -var stream = new tream.Transform({ +var stream = new stream.Transform({ transform: function transformCallback(chunk, _, next) { // part 1 this.push(chunk); @@ -101,4 +103,7 @@ t.write(4); t.end(7, common.mustCall(function () { state++; assert.strictEqual(state, 14, 'endMethodCallback'); -}, 1)); \ No newline at end of file +}, 1)); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-flush-data.js b/test/parallel/test-stream-transform-flush-data.js index 2dd4ffc64c..0680630f88 100644 --- a/test/parallel/test-stream-transform-flush-data.js +++ b/test/parallel/test-stream-transform-flush-data.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -24,4 +26,7 @@ var t = new Transform({ t.end(bufferShim.from('blerg')); t.on('data', function (data) { assert.strictEqual(data.toString(), expected); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-objectmode-falsey-value.js b/test/parallel/test-stream-transform-objectmode-falsey-value.js index 0e95c48d0e..4d21263c82 100644 --- a/test/parallel/test-stream-transform-objectmode-falsey-value.js +++ b/test/parallel/test-stream-transform-objectmode-falsey-value.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -50,4 +52,7 @@ var int = setInterval(common.mustCall(function () { } else { src.write(i++); } -}, expect.length + 1), 1); \ No newline at end of file +}, expect.length + 1), 1); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-split-highwatermark.js b/test/parallel/test-stream-transform-split-highwatermark.js index 2c3b034a81..6306557c63 100644 --- a/test/parallel/test-stream-transform-split-highwatermark.js +++ b/test/parallel/test-stream-transform-split-highwatermark.js @@ -1,7 +1,9 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); +var common = require('../common'); var assert = require('assert/'); var _require = require('../../'), @@ -59,18 +61,40 @@ testTransform(0, 0, { writableHighWaterMark: 777 }); -// test undefined, null, NaN -[undefined, null, NaN].forEach(function (v) { +// test undefined, null +[undefined, null].forEach(function (v) { testTransform(DEFAULT, DEFAULT, { readableHighWaterMark: v }); testTransform(DEFAULT, DEFAULT, { writableHighWaterMark: v }); testTransform(666, DEFAULT, { highWaterMark: v, readableHighWaterMark: 666 }); testTransform(DEFAULT, 777, { highWaterMark: v, writableHighWaterMark: 777 }); }); +// test NaN +{ + common.expectsError(function () { + new Transform({ readableHighWaterMark: NaN }); + }, { + type: TypeError, + code: 'ERR_INVALID_OPT_VALUE', + message: 'The value "NaN" is invalid for option "readableHighWaterMark"' + }); + + common.expectsError(function () { + new Transform({ writableHighWaterMark: NaN }); + }, { + type: TypeError, + code: 'ERR_INVALID_OPT_VALUE', + message: 'The value "NaN" is invalid for option "writableHighWaterMark"' + }); +} + // test non Duplex streams ignore the options { var r = new Readable({ readableHighWaterMark: 666 }); assert.strictEqual(r._readableState.highWaterMark, DEFAULT); var w = new Writable({ writableHighWaterMark: 777 }); assert.strictEqual(w._writableState.highWaterMark, DEFAULT); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-transform-split-objectmode.js b/test/parallel/test-stream-transform-split-objectmode.js index 097c3d789f..ef61a3a4de 100644 --- a/test/parallel/test-stream-transform-split-objectmode.js +++ b/test/parallel/test-stream-transform-split-objectmode.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -75,4 +77,7 @@ serializer.write({ val: 42 }); process.on('exit', function () { assert.strictEqual(serialized[0], 42); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-uint8array.js b/test/parallel/test-stream-uint8array.js index def15cd61a..463cc82fc6 100644 --- a/test/parallel/test-stream-uint8array.js +++ b/test/parallel/test-stream-uint8array.js @@ -1,3 +1,5 @@ +'use strict'; + function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } /**/ @@ -104,4 +106,7 @@ var GHI = new Uint8Array([0x47, 0x48, 0x49]); var out = _readable.read(); assert.strictEqual(out, 'ABCDEF'); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-unpipe-event.js b/test/parallel/test-stream-unpipe-event.js index 2f7ef2567b..441de4b3c4 100644 --- a/test/parallel/test-stream-unpipe-event.js +++ b/test/parallel/test-stream-unpipe-event.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -129,4 +131,7 @@ var NeverEndReadable = function (_Readable2) { setImmediate(function () { assert.strictEqual(_src5._readableState.pipesCount, 0); }); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-unshift-empty-chunk.js b/test/parallel/test-stream-unshift-empty-chunk.js index fcc5457ddd..41b19e001d 100644 --- a/test/parallel/test-stream-unshift-empty-chunk.js +++ b/test/parallel/test-stream-unshift-empty-chunk.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -60,5 +62,8 @@ var expect = ['xxxxxxxxxx', 'yyyyy', 'xxxxxxxxxx', 'yyyyy', 'xxxxxxxxxx', 'yyyyy r.on('end', function () { assert.deepStrictEqual(seen, expect); - console.log('ok'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-unshift-read-race.js b/test/parallel/test-stream-unshift-read-race.js index 0e615db95d..c5db217a86 100644 --- a/test/parallel/test-stream-unshift-read-race.js +++ b/test/parallel/test-stream-unshift-read-race.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -53,7 +55,7 @@ r._read = function (n) { function push(fast) { assert(!pushedNull, 'push() after null push'); - var c = pos >= data.length ? null : data.slice(pos, Math.min(pos + n, data.length)); + var c = pos >= data.length ? null : data.slice(pos, pos + n); pushedNull = c === null; if (fast) { pos += n; @@ -70,9 +72,13 @@ r._read = function (n) { }; function pushError() { - assert.throws(function () { + common.expectsError(function () { r.push(bufferShim.allocUnsafe(1)); - }, /^Error: stream\.push\(\) after EOF$/); + }, { + code: 'ERR_STREAM_PUSH_AFTER_EOF', + type: Error, + message: 'stream.push() after EOF' + }); } var w = stream.Writable(); @@ -83,9 +89,13 @@ w._write = function (chunk, encoding, cb) { }; r.on('end', common.mustCall(function () { - assert.throws(function () { + common.expectsError(function () { r.unshift(bufferShim.allocUnsafe(1)); - }, /^Error: stream\.unshift\(\) after end event$/); + }, { + code: 'ERR_STREAM_UNSHIFT_AFTER_END_EVENT', + type: Error, + message: 'stream.unshift() after end event' + }); w.end(); })); @@ -126,5 +136,8 @@ w.on('finish', common.mustCall(function () { process.on('exit', function () { assert.strictEqual(written.length, 18); - console.log('ok'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-change-default-encoding.js b/test/parallel/test-stream-writable-change-default-encoding.js index 05f37cc014..86ef2f3f59 100644 --- a/test/parallel/test-stream-writable-change-default-encoding.js +++ b/test/parallel/test-stream-writable-change-default-encoding.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -28,7 +30,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); +var common = require('../common'); var assert = require('assert/'); var stream = require('../../'); @@ -70,12 +72,16 @@ var MyWritable = function (_stream$Writable) { m.end(); })(); -assert.throws(function changeDefaultEncodingToInvalidValue() { +common.expectsError(function changeDefaultEncodingToInvalidValue() { var m = new MyWritable(function (isBuffer, type, enc) {}, { decodeStrings: false }); m.setDefaultEncoding({}); m.write('bar'); m.end(); -}, /^TypeError: Unknown encoding: \[object Object\]$/); +}, { + type: TypeError, + code: 'ERR_UNKNOWN_ENCODING', + message: 'Unknown encoding: [object Object]' +}); (function checkVairableCaseEncoding() { var m = new MyWritable(function (isBuffer, type, enc) { @@ -84,4 +90,7 @@ assert.throws(function changeDefaultEncodingToInvalidValue() { m.setDefaultEncoding('AsCii'); m.write('bar'); m.end(); -})(); \ No newline at end of file +})(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-constructor-set-methods.js b/test/parallel/test-stream-writable-constructor-set-methods.js index aa88674714..8b66ea35f8 100644 --- a/test/parallel/test-stream-writable-constructor-set-methods.js +++ b/test/parallel/test-stream-writable-constructor-set-methods.js @@ -1,37 +1,47 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); -var assert = require('assert/'); +var common = require('../common'); + +var _require = require('assert/'), + strictEqual = _require.strictEqual; + +var _require2 = require('../../'), + Writable = _require2.Writable; -var Writable = require('../../').Writable; +var w = new Writable(); -var _writeCalled = false; -function _write(d, e, n) { - _writeCalled = true; -} +w.on('error', common.expectsError({ + type: Error, + code: 'ERR_METHOD_NOT_IMPLEMENTED', + message: 'The _write() method is not implemented' +})); -var w = new Writable({ write: _write }); w.end(bufferShim.from('blerg')); -var _writevCalled = false; -var dLength = 0; -function _writev(d, n) { - dLength = d.length; - _writevCalled = true; -} +var _write = common.mustCall(function (chunk, _, next) { + next(); +}); -var w2 = new Writable({ writev: _writev }); -w2.cork(); +var _writev = common.mustCall(function (chunks, next) { + strictEqual(chunks.length, 2); + next(); +}); + +var w2 = new Writable({ write: _write, writev: _writev }); + +strictEqual(w2._write, _write); +strictEqual(w2._writev, _writev); +w2.write(bufferShim.from('blerg')); + +w2.cork(); w2.write(bufferShim.from('blerg')); w2.write(bufferShim.from('blerg')); -w2.end(); -process.on('exit', function () { - assert.strictEqual(w._write, _write); - assert(_writeCalled); - assert.strictEqual(w2._writev, _writev); - assert.strictEqual(dLength, 2); - assert(_writevCalled); +w2.end(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-decoded-encoding.js b/test/parallel/test-stream-writable-decoded-encoding.js index e9c71ffa39..0a44a3be32 100644 --- a/test/parallel/test-stream-writable-decoded-encoding.js +++ b/test/parallel/test-stream-writable-decoded-encoding.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -71,4 +73,7 @@ var MyWritable = function (_stream$Writable) { }, { decodeStrings: false }); _m.write('some-text', 'utf8'); _m.end(); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-destroy.js b/test/parallel/test-stream-writable-destroy.js index 3aeff6c445..333134d289 100644 --- a/test/parallel/test-stream-writable-destroy.js +++ b/test/parallel/test-stream-writable-destroy.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -19,7 +21,8 @@ var _require2 = require('util'), } }); - write.on('finish', common.mustCall()); + write.on('finish', common.mustNotCall()); + write.on('close', common.mustCall()); write.destroy(); assert.strictEqual(write.destroyed, true); @@ -34,7 +37,8 @@ var _require2 = require('util'), var expected = new Error('kaboom'); - _write.on('finish', common.mustCall()); + _write.on('finish', common.mustNotCall()); + _write.on('close', common.mustCall()); _write.on('error', common.mustCall(function (err) { assert.strictEqual(err, expected); })); @@ -58,6 +62,7 @@ var _require2 = require('util'), var _expected = new Error('kaboom'); _write2.on('finish', common.mustNotCall('no finish event')); + _write2.on('close', common.mustCall()); _write2.on('error', common.mustCall(function (err) { assert.strictEqual(err, _expected); })); @@ -81,6 +86,7 @@ var _require2 = require('util'), var _expected2 = new Error('kaboom'); _write3.on('finish', common.mustNotCall('no finish event')); + _write3.on('close', common.mustCall()); // error is swallowed by the custom _destroy _write3.on('error', common.mustNotCall('no error event')); @@ -125,6 +131,7 @@ var _require2 = require('util'), var fail = common.mustNotCall('no finish event'); _write5.on('finish', fail); + _write5.on('close', common.mustCall()); _write5.destroy(); @@ -147,6 +154,7 @@ var _require2 = require('util'), cb(_expected3); }); + _write6.on('close', common.mustCall()); _write6.on('finish', common.mustNotCall('no finish event')); _write6.on('error', common.mustCall(function (err) { assert.strictEqual(err, _expected3); @@ -164,6 +172,7 @@ var _require2 = require('util'), } }); + _write7.on('close', common.mustCall()); _write7.on('error', common.mustCall()); _write7.destroy(new Error('kaboom 1')); @@ -183,7 +192,7 @@ var _require2 = require('util'), assert.strictEqual(_write8.destroyed, true); // the internal destroy() mechanism should not be triggered - _write8.on('finish', common.mustNotCall()); + _write8.on('close', common.mustNotCall()); _write8.destroy(); } @@ -214,4 +223,23 @@ var _require2 = require('util'), _write9.destroy(_expected4, common.mustCall(function (err) { assert.strictEqual(_expected4, err); })); -} \ No newline at end of file +} + +{ + // Checks that `._undestroy()` restores the state so that `final` will be + // called again. + var _write10 = new Writable({ + write: common.mustNotCall(), + final: common.mustCall(function (cb) { + return cb(); + }, 2) + }); + + _write10.end(); + _write10.destroy(); + _write10._undestroy(); + _write10.end(); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-ended-state.js b/test/parallel/test-stream-writable-ended-state.js index dd2e332d02..f871205874 100644 --- a/test/parallel/test-stream-writable-ended-state.js +++ b/test/parallel/test-stream-writable-ended-state.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -20,4 +22,7 @@ writable.end('testing ended state', common.mustCall(function () { assert.strictEqual(writable._writableState.ended, true); })); -assert.strictEqual(writable._writableState.ended, true); \ No newline at end of file +assert.strictEqual(writable._writableState.ended, true); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-finished-state.js b/test/parallel/test-stream-writable-finished-state.js index 88566cfd85..e3a61127ea 100644 --- a/test/parallel/test-stream-writable-finished-state.js +++ b/test/parallel/test-stream-writable-finished-state.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -21,4 +23,7 @@ writable.on('finish', common.mustCall(function () { writable.end('testing finished state', common.mustCall(function () { assert.strictEqual(writable._writableState.finished, true); -})); \ No newline at end of file +})); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-needdrain-state.js b/test/parallel/test-stream-writable-needdrain-state.js index adca330e48..b01ee50a0d 100644 --- a/test/parallel/test-stream-writable-needdrain-state.js +++ b/test/parallel/test-stream-writable-needdrain-state.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -22,4 +24,7 @@ transform.write('asdasd', common.mustCall(function () { assert.strictEqual(transform._writableState.needDrain, false); })); -assert.strictEqual(transform._writableState.needDrain, true); \ No newline at end of file +assert.strictEqual(transform._writableState.needDrain, true); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-null.js b/test/parallel/test-stream-writable-null.js index bfafc7ff55..ab2dfcbffa 100644 --- a/test/parallel/test-stream-writable-null.js +++ b/test/parallel/test-stream-writable-null.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -7,7 +9,7 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); +var common = require('../common'); var assert = require('assert/'); var stream = require('../../'); @@ -29,47 +31,52 @@ var MyWritable = function (_stream$Writable) { return MyWritable; }(stream.Writable); -assert.throws(function () { +common.expectsError(function () { var m = new MyWritable({ objectMode: true }); m.write(null, function (err) { return assert.ok(err); }); -}, /^TypeError: May not write null values to stream$/); -assert.doesNotThrow(function () { - var m = new MyWritable({ objectMode: true }).on('error', function (e) { - assert.ok(e); - }); - m.write(null, function (err) { - assert.ok(err); - }); +}, { + code: 'ERR_STREAM_NULL_VALUES', + type: TypeError, + message: 'May not write null values to stream' }); -assert.throws(function () { +{ + // Should not throw. + var m = new MyWritable({ objectMode: true }).on('error', assert); + m.write(null, assert); +} + +common.expectsError(function () { var m = new MyWritable(); m.write(false, function (err) { return assert.ok(err); }); -}, /^TypeError: Invalid non-string\/buffer chunk$/); -assert.doesNotThrow(function () { - var m = new MyWritable().on('error', function (e) { - assert.ok(e); - }); - m.write(false, function (err) { - assert.ok(err); - }); +}, { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError }); -assert.doesNotThrow(function () { - var m = new MyWritable({ objectMode: true }); - m.write(false, function (err) { - return assert.ifError(err); - }); -}); -assert.doesNotThrow(function () { - var m = new MyWritable({ objectMode: true }).on('error', function (e) { +{ + // Should not throw. + var _m = new MyWritable().on('error', assert); + _m.write(false, assert); +} + +{ + // Should not throw. + var _m2 = new MyWritable({ objectMode: true }); + _m2.write(false, assert.ifError); +} + +{ + // Should not throw. + var _m3 = new MyWritable({ objectMode: true }).on('error', function (e) { assert.ifError(e || new Error('should not get here')); }); - m.write(false, function (err) { - assert.ifError(err); - }); + _m3.write(false, assert.ifError); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-write-cb-twice.js b/test/parallel/test-stream-writable-write-cb-twice.js new file mode 100644 index 0000000000..582f8264c3 --- /dev/null +++ b/test/parallel/test-stream-writable-write-cb-twice.js @@ -0,0 +1,58 @@ +'use strict'; + +/**/ +var bufferShim = require('safe-buffer').Buffer; +/**/ +var common = require('../common'); + +var _require = require('../../'), + Writable = _require.Writable; + +{ + // Sync + Sync + var writable = new Writable({ + write: common.mustCall(function (buf, enc, cb) { + cb(); + common.expectsError(cb, { + code: 'ERR_MULTIPLE_CALLBACK', + type: Error + }); + }) + }); + writable.write('hi'); +} + +{ + // Sync + Async + var _writable = new Writable({ + write: common.mustCall(function (buf, enc, cb) { + cb(); + process.nextTick(function () { + common.expectsError(cb, { + code: 'ERR_MULTIPLE_CALLBACK', + type: Error + }); + }); + }) + }); + _writable.write('hi'); +} + +{ + // Async + Async + var _writable2 = new Writable({ + write: common.mustCall(function (buf, enc, cb) { + process.nextTick(cb); + process.nextTick(function () { + common.expectsError(cb, { + code: 'ERR_MULTIPLE_CALLBACK', + type: Error + }); + }); + }) + }); + _writable2.write('hi'); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writable-write-writev-finish.js b/test/parallel/test-stream-writable-write-writev-finish.js index e5a8f65a9e..8adc5a4d1c 100644 --- a/test/parallel/test-stream-writable-write-writev-finish.js +++ b/test/parallel/test-stream-writable-write-writev-finish.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -155,4 +157,31 @@ var stream = require('../../'); done(new Error()); }; _rs.pipe(_ws); -} \ No newline at end of file +} + +{ + var w = new stream.Writable(); + w._write = function (chunk, encoding, cb) { + process.nextTick(cb); + }; + w.on('error', common.mustCall()); + w.on('prefinish', function () { + w.write("shouldn't write in prefinish listener"); + }); + w.end(); +} + +{ + var _w = new stream.Writable(); + _w._write = function (chunk, encoding, cb) { + process.nextTick(cb); + }; + _w.on('error', common.mustCall()); + _w.on('finish', function () { + _w.write("should't write in finish listener"); + }); + _w.end(); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writableState-ending.js b/test/parallel/test-stream-writableState-ending.js index fd423b0d44..44b8d0b586 100644 --- a/test/parallel/test-stream-writableState-ending.js +++ b/test/parallel/test-stream-writableState-ending.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -26,11 +28,17 @@ writable.on('finish', function () { testStates(true, true, true); }); -writable.end('testing function end()', function () { +var result = writable.end('testing function end()', function () { // ending, finished, ended = true. testStates(true, true, true); }); +// end returns the writable instance +assert.strictEqual(result, writable); + // ending, ended = true. // finished = false. -testStates(true, false, true); \ No newline at end of file +testStates(true, false, true); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js b/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js index 376bf7c673..6d6f5b649d 100644 --- a/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js +++ b/test/parallel/test-stream-writableState-uncorked-bufferedRequestCount.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -9,7 +11,7 @@ var stream = require('../../'); var writable = new stream.Writable(); writable._writev = common.mustCall(function (chunks, cb) { - assert.strictEqual(chunks.length, 2, 'two chunks to write'); + assert.strictEqual(chunks.length, 2); cb(); }, 1); @@ -56,4 +58,7 @@ function uncork() { // end causes an uncork() as well assert.strictEqual(writable._writableState.corked, 0); assert.strictEqual(writable._writableState.bufferedRequestCount, 0); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-write-final.js b/test/parallel/test-stream-write-final.js index bd3dafecfb..1264389242 100644 --- a/test/parallel/test-stream-write-final.js +++ b/test/parallel/test-stream-write-final.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -23,4 +25,7 @@ w.on('finish', common.mustCall(function () { assert(shutdown); })); w.write(bufferShim.allocUnsafe(1)); -w.end(bufferShim.allocUnsafe(0)); \ No newline at end of file +w.end(bufferShim.allocUnsafe(0)); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream-writev.js b/test/parallel/test-stream-writev.js index 478121e880..9fe98fc592 100644 --- a/test/parallel/test-stream-writev.js +++ b/test/parallel/test-stream-writev.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -40,11 +42,11 @@ run(); function run() { var t = queue.pop(); - if (t) test(t[0], t[1], t[2], run);else console.log('ok'); + if (t) test(t[0], t[1], t[2], run);else require('tap').pass(); } function test(decode, uncork, multi, next) { - console.log('# decode=' + decode + ' uncork=' + uncork + ' multi=' + multi); + require('tap').test('# decode=' + decode + ' uncork=' + uncork + ' multi=' + multi); var counter = 0; var expectCount = 0; function cnt(msg) { @@ -65,7 +67,7 @@ function test(decode, uncork, multi, next) { chunk: [119, 111, 114, 108, 100] }, { encoding: 'buffer', chunk: [33] }, { encoding: 'buffer', chunk: [10, 97, 110, 100, 32, 116, 104, 101, 110, 46, 46, 46] }, { encoding: 'buffer', - chunk: [250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173] }] : [{ encoding: 'ascii', chunk: 'hello, ' }, { encoding: 'utf8', chunk: 'world' }, { encoding: 'buffer', chunk: [33] }, { encoding: 'binary', chunk: '\nand then...' }, { encoding: 'hex', chunk: 'facebea7deadbeefdecafbad' }]; + chunk: [250, 206, 190, 167, 222, 173, 190, 239, 222, 202, 251, 173] }] : [{ encoding: 'ascii', chunk: 'hello, ' }, { encoding: 'utf8', chunk: 'world' }, { encoding: 'buffer', chunk: [33] }, { encoding: 'latin1', chunk: '\nand then...' }, { encoding: 'hex', chunk: 'facebea7deadbeefdecafbad' }]; var actualChunks = void 0; w._writev = function (chunks, cb) { @@ -85,7 +87,7 @@ function test(decode, uncork, multi, next) { if (multi) w.cork(); w.write(bufferShim.from('!'), 'buffer', cnt('!')); - w.write('\nand then...', 'binary', cnt('and then')); + w.write('\nand then...', 'latin1', cnt('and then')); if (multi) w.uncork(); @@ -101,4 +103,7 @@ function test(decode, uncork, multi, next) { assert.deepStrictEqual(expectChunks, actualChunks); next(); }); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-base64-single-char-read-end.js b/test/parallel/test-stream2-base64-single-char-read-end.js index cde122d3be..e526bb1ac0 100644 --- a/test/parallel/test-stream2-base64-single-char-read-end.js +++ b/test/parallel/test-stream2-base64-single-char-read-end.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -56,4 +58,7 @@ src.pipe(dst); var timeout = setTimeout(function () { assert.fail('timed out waiting for _write'); -}, 100); \ No newline at end of file +}, 100); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-basic.js b/test/parallel/test-stream2-basic.js index 0a0b364ed3..9e8f0bec27 100644 --- a/test/parallel/test-stream2-basic.js +++ b/test/parallel/test-stream2-basic.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -82,8 +84,6 @@ var TestReader = function (_R) { return TestReader; }(R); -///// - var TestWriter = function (_EE) { _inherits(TestWriter, _EE); @@ -195,10 +195,10 @@ forEach([1, 2, 3, 4, 5, 6, 7, 8, 9], function (SPLIT) { var _expect2 = ['xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx', 'xxxxx']; _w[0].on('end', common.mustCall(function (received) { - assert.deepStrictEqual(received, _expect2, 'first'); + assert.deepStrictEqual(received, _expect2); })); _w[1].on('end', common.mustCall(function (received) { - assert.deepStrictEqual(received, _expect2, 'second'); + assert.deepStrictEqual(received, _expect2); })); _r2.pipe(_w[0]); @@ -395,4 +395,7 @@ function forEach(xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-compatibility.js b/test/parallel/test-stream2-compatibility.js index 4737f9a282..58ed5d7e93 100644 --- a/test/parallel/test-stream2-compatibility.js +++ b/test/parallel/test-stream2-compatibility.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -62,7 +64,7 @@ var TestReader = function (_R) { var reader = new TestReader(); setImmediate(function () { assert.strictEqual(ondataCalled, 1); - console.log('ok'); + require('tap').pass(); reader.push(null); }); @@ -91,5 +93,8 @@ var writer = new TestWriter(); process.on('exit', function () { assert.strictEqual(reader.readable, false); assert.strictEqual(writer.writable, false); - console.log('ok'); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream2-decode-partial.js b/test/parallel/test-stream2-decode-partial.js index a9a5c55942..4a96aabce4 100644 --- a/test/parallel/test-stream2-decode-partial.js +++ b/test/parallel/test-stream2-decode-partial.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -22,4 +24,7 @@ readable.on('data', function (data) { process.on('exit', function () { assert.strictEqual(buf, '€¢'); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream2-finish-pipe.js b/test/parallel/test-stream2-finish-pipe.js index 1566ee3652..2a343dcbb5 100644 --- a/test/parallel/test-stream2-finish-pipe.js +++ b/test/parallel/test-stream2-finish-pipe.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -40,4 +42,7 @@ r.pipe(w); // This might sound unrealistic, but it happens in net.js. When // `socket.allowHalfOpen === false`, EOF will cause `.destroySoon()` call which // ends the writable side of net.Socket. -w.end(); \ No newline at end of file +w.end(); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-large-read-stall.js b/test/parallel/test-stream2-large-read-stall.js index deabcf1b9c..72623b87e5 100644 --- a/test/parallel/test-stream2-large-read-stall.js +++ b/test/parallel/test-stream2-large-read-stall.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -68,4 +70,7 @@ function push() { ;false && console.error(' push #' + pushes); if (r.push(bufferShim.allocUnsafe(PUSHSIZE))) setTimeout(push, 1); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-objects.js b/test/parallel/test-stream2-objects.js index 5665f5e8ef..8196b10a38 100644 --- a/test/parallel/test-stream2-objects.js +++ b/test/parallel/test-stream2-objects.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -100,9 +102,9 @@ function fromArray(list) { { // Verify that objects can be asynchronously read var _r4 = new Readable({ objectMode: true }); - var _list = [{ one: '1' }, { two: '2' }]; + var _list2 = [{ one: '1' }, { two: '2' }]; _r4._read = function (n) { - var item = _list.shift(); + var item = _list2.shift(); process.nextTick(function () { _r4.push(item || null); }); @@ -119,14 +121,14 @@ function fromArray(list) { objectMode: true }); _r5._read = common.mustNotCall(); - var _list2 = ['one', 'two', 'three']; - forEach(_list2, function (str) { + var _list3 = ['one', 'two', 'three']; + forEach(_list3, function (str) { _r5.push(str); }); _r5.push(null); _r5.pipe(toArray(common.mustCall(function (array) { - assert.deepStrictEqual(array, _list2); + assert.deepStrictEqual(array, _list3); }))); } @@ -169,13 +171,13 @@ function fromArray(list) { objectMode: true }); var calls = 0; - var _list3 = ['1', '2', '3', '4', '5', '6', '7', '8']; + var _list4 = ['1', '2', '3', '4', '5', '6', '7', '8']; _r8._read = function (n) { calls++; }; - forEach(_list3, function (c) { + forEach(_list4, function (c) { _r8.push(c); }); @@ -223,15 +225,15 @@ function fromArray(list) { { // Verify that multiple objects can be written to stream var _w = new Writable({ objectMode: true }); - var _list4 = []; + var _list5 = []; _w._write = function (chunk, encoding, cb) { - _list4.push(chunk); + _list5.push(chunk); cb(); }; _w.on('finish', common.mustCall(function () { - assert.deepStrictEqual(_list4, [0, 1, 2, 3, 4]); + assert.deepStrictEqual(_list5, [0, 1, 2, 3, 4]); })); _w.write(0); @@ -247,15 +249,15 @@ function fromArray(list) { var _w2 = new Writable({ objectMode: true }); - var _list5 = []; + var _list6 = []; _w2._write = function (chunk, encoding, cb) { - _list5.push(chunk); + _list6.push(chunk); process.nextTick(cb); }; _w2.on('finish', common.mustCall(function () { - assert.deepStrictEqual(_list5, ['0', '1', '2', '3', '4']); + assert.deepStrictEqual(_list6, ['0', '1', '2', '3', '4']); })); _w2.write('0'); @@ -294,4 +296,7 @@ function forEach(xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-pipe-error-handling.js b/test/parallel/test-stream2-pipe-error-handling.js index 4ccad3dfe2..d2eae1faea 100644 --- a/test/parallel/test-stream2-pipe-error-handling.js +++ b/test/parallel/test-stream2-pipe-error-handling.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -105,4 +107,7 @@ var stream = require('../../'); assert.strictEqual(_gotErr, _err); assert.strictEqual(_unpipedSource, _source); assert.strictEqual(_unpipedDest, _dest); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-pipe-error-once-listener.js b/test/parallel/test-stream2-pipe-error-once-listener.js index 2b8e467cf3..a52ef2cfd0 100644 --- a/test/parallel/test-stream2-pipe-error-once-listener.js +++ b/test/parallel/test-stream2-pipe-error-once-listener.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -71,11 +73,14 @@ var write = new Write(); write.once('error', function () {}); write.once('alldone', function (err) { - console.log('ok'); + require('tap').pass(); }); process.on('exit', function (c) { console.error('error thrown even with listener'); }); -read.pipe(write); \ No newline at end of file +read.pipe(write); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-push.js b/test/parallel/test-stream2-push.js index 358e57a7a5..efc84a1846 100644 --- a/test/parallel/test-stream2-push.js +++ b/test/parallel/test-stream2-push.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -52,7 +54,7 @@ stream.on('end', function () { source.on('data', function (chunk) { var ret = stream.push(chunk); - console.error('data', stream._readableState.length); + console.error('data', stream.readableLength); if (!ret) readStop(); }); @@ -115,7 +117,7 @@ function data() { function finish() { console.error('finish'); assert.deepStrictEqual(written, expectWritten); - console.log('ok'); + require('tap').pass(); } function end() { @@ -125,4 +127,7 @@ function end() { setImmediate(function () { assert(ended); }); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-read-sync-stack.js b/test/parallel/test-stream2-read-sync-stack.js index d0400d52d3..0afe19954d 100644 --- a/test/parallel/test-stream2-read-sync-stack.js +++ b/test/parallel/test-stream2-read-sync-stack.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -38,10 +40,13 @@ r._read = function (n) { }; r.on('readable', function onReadable() { - if (!(r._readableState.length % 256)) console.error('readable', r._readableState.length); + if (!(r.readableLength % 256)) console.error('readable', r.readableLength); r.read(N * 2); }); r.on('end', common.mustCall()); -r.read(0); \ No newline at end of file +r.read(0); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-readable-empty-buffer-no-eof.js b/test/parallel/test-stream2-readable-empty-buffer-no-eof.js index 8371ac1133..177d7ad64e 100644 --- a/test/parallel/test-stream2-readable-empty-buffer-no-eof.js +++ b/test/parallel/test-stream2-readable-empty-buffer-no-eof.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -88,7 +90,7 @@ function test1() { process.on('exit', function () { assert.deepStrictEqual(results, ['xxxxx', 'xxxxx', 'EOF']); - console.log('ok'); + require('tap').pass(); }); } @@ -115,6 +117,9 @@ function test2() { process.on('exit', function () { assert.deepStrictEqual(results, ['eHh4', 'eHg=', 'EOF']); - console.log('ok'); + require('tap').pass(); }); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-readable-from-list.js b/test/parallel/test-stream2-readable-from-list.js index 169d8f8168..cd357992d5 100644 --- a/test/parallel/test-stream2-readable-from-list.js +++ b/test/parallel/test-stream2-readable-from-list.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -26,7 +28,7 @@ var bufferShim = require('safe-buffer').Buffer; require('../common'); var assert = require('assert/'); var fromList = require('../../lib/_stream_readable')._fromList; -var BufferList = require('../../lib/internal/streams/BufferList'); +var BufferList = require('../../lib/internal/streams/buffer_list'); function bufferListFromArray(arr) { var bl = new BufferList(); @@ -62,25 +64,28 @@ function bufferListFromArray(arr) { { // Verify behavior with strings - var _list = ['foog', 'bark', 'bazy', 'kuel']; - _list = bufferListFromArray(_list); + var _list2 = ['foog', 'bark', 'bazy', 'kuel']; + _list2 = bufferListFromArray(_list2); // read more than the first element. - var _ret = fromList(6, { buffer: _list, length: 16, decoder: true }); + var _ret = fromList(6, { buffer: _list2, length: 16, decoder: true }); assert.strictEqual(_ret, 'foogba'); // read exactly the first element. - _ret = fromList(2, { buffer: _list, length: 10, decoder: true }); + _ret = fromList(2, { buffer: _list2, length: 10, decoder: true }); assert.strictEqual(_ret, 'rk'); // read less than the first element. - _ret = fromList(2, { buffer: _list, length: 8, decoder: true }); + _ret = fromList(2, { buffer: _list2, length: 8, decoder: true }); assert.strictEqual(_ret, 'ba'); // read more than we have. - _ret = fromList(100, { buffer: _list, length: 6, decoder: true }); + _ret = fromList(100, { buffer: _list2, length: 6, decoder: true }); assert.strictEqual(_ret, 'zykuel'); // all consumed. - assert.deepStrictEqual(_list, new BufferList()); -} \ No newline at end of file + assert.deepStrictEqual(_list2, new BufferList()); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-readable-legacy-drain.js b/test/parallel/test-stream2-readable-legacy-drain.js index 8c249c1f3a..59fdc73113 100644 --- a/test/parallel/test-stream2-readable-legacy-drain.js +++ b/test/parallel/test-stream2-readable-legacy-drain.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -61,4 +63,7 @@ r.on('readable', function () { w.emit('drain'); }); -r.pipe(w); \ No newline at end of file +r.pipe(w); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-readable-non-empty-end.js b/test/parallel/test-stream2-readable-non-empty-end.js index f9045ae513..4a70c8c42a 100644 --- a/test/parallel/test-stream2-readable-non-empty-end.js +++ b/test/parallel/test-stream2-readable-non-empty-end.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -71,4 +73,7 @@ function next() { assert.strictEqual(r.length, 1); r = test.read(); assert.strictEqual(r, null); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-readable-wrap-empty.js b/test/parallel/test-stream2-readable-wrap-empty.js index 165af42be5..15474eb989 100644 --- a/test/parallel/test-stream2-readable-wrap-empty.js +++ b/test/parallel/test-stream2-readable-wrap-empty.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -35,4 +37,7 @@ var newStream = new Readable().wrap(oldStream); newStream.on('readable', function () {}).on('end', common.mustCall()); -oldStream.emit('end'); \ No newline at end of file +oldStream.emit('end'); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-set-encoding.js b/test/parallel/test-stream2-set-encoding.js index ebf1fd3f0e..b6027ed866 100644 --- a/test/parallel/test-stream2-set-encoding.js +++ b/test/parallel/test-stream2-set-encoding.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -224,4 +226,7 @@ var TestReader = function (_R) { // Verify chaining behavior var _tr8 = new TestReader(100); assert.deepStrictEqual(_tr8.setEncoding('utf8'), _tr8); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-transform.js b/test/parallel/test-stream2-transform.js index 62aa1d2bdb..580a34292d 100644 --- a/test/parallel/test-stream2-transform.js +++ b/test/parallel/test-stream2-transform.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -45,10 +47,10 @@ var Transform = require('../../lib/_stream_transform'); } tx.end(); - assert.strictEqual(tx._readableState.length, 10); + assert.strictEqual(tx.readableLength, 10); assert.strictEqual(transformed, 10); assert.strictEqual(tx._transformState.writechunk.length, 5); - assert.deepStrictEqual(tx._writableState.getBuffer().map(function (c) { + assert.deepStrictEqual(tx.writableBuffer.map(function (c) { return c.chunk.length; }), [6, 7, 8, 9, 10]); } @@ -177,7 +179,7 @@ var Transform = require('../../lib/_stream_transform'); } { - // Verify assymetric transform (expand) + // Verify asymmetric transform (expand) var _pt7 = new Transform(); // emit each chunk 2 times. @@ -209,7 +211,7 @@ var Transform = require('../../lib/_stream_transform'); } { - // Verify assymetric trasform (compress) + // Verify asymmetric transform (compress) var _pt8 = new Transform(); // each output is the first char of 3 consecutive chunks, @@ -265,7 +267,7 @@ var Transform = require('../../lib/_stream_transform'); // this tests for a stall when data is written to a full stream // that has empty transforms. { - // Verify compex transform behavior + // Verify complex transform behavior var count = 0; var saved = null; var _pt9 = new Transform({ highWaterMark: 3 }); @@ -306,25 +308,26 @@ var Transform = require('../../lib/_stream_transform'); _pt10.write(bufferShim.from('foog')); _pt10.write(bufferShim.from('bark')); - assert.strictEqual(emits, 1); + assert.strictEqual(emits, 0); assert.strictEqual(_pt10.read(5).toString(), 'foogb'); assert.strictEqual(String(_pt10.read(5)), 'null'); + assert.strictEqual(emits, 0); _pt10.write(bufferShim.from('bazy')); _pt10.write(bufferShim.from('kuel')); - assert.strictEqual(emits, 2); + assert.strictEqual(emits, 0); assert.strictEqual(_pt10.read(5).toString(), 'arkba'); assert.strictEqual(_pt10.read(5).toString(), 'zykue'); assert.strictEqual(_pt10.read(5), null); _pt10.end(); - assert.strictEqual(emits, 3); + assert.strictEqual(emits, 1); assert.strictEqual(_pt10.read(5).toString(), 'l'); assert.strictEqual(_pt10.read(5), null); - assert.strictEqual(emits, 3); + assert.strictEqual(emits, 1); } { @@ -338,7 +341,7 @@ var Transform = require('../../lib/_stream_transform'); _pt11.write(bufferShim.from('foog')); _pt11.write(bufferShim.from('bark')); - assert.strictEqual(_emits, 1); + assert.strictEqual(_emits, 0); assert.strictEqual(_pt11.read(5).toString(), 'foogb'); assert.strictEqual(_pt11.read(5), null); @@ -352,7 +355,7 @@ var Transform = require('../../lib/_stream_transform'); _pt11.once('readable', common.mustCall(function () { assert.strictEqual(_pt11.read(5).toString(), 'l'); assert.strictEqual(_pt11.read(5), null); - assert.strictEqual(_emits, 4); + assert.strictEqual(_emits, 3); })); _pt11.end(); })); @@ -465,4 +468,7 @@ function forEach(xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-unpipe-drain.js b/test/parallel/test-stream2-unpipe-drain.js index 160ded4f06..afa334f204 100644 --- a/test/parallel/test-stream2-unpipe-drain.js +++ b/test/parallel/test-stream2-unpipe-drain.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -96,4 +98,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" assert.strictEqual(src1.reads, 2); assert.strictEqual(src2.reads, 2); }); -})(); \ No newline at end of file +})();require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream2-unpipe-leak.js b/test/parallel/test-stream2-unpipe-leak.js index e77e939ed1..dcc3aed100 100644 --- a/test/parallel/test-stream2-unpipe-leak.js +++ b/test/parallel/test-stream2-unpipe-leak.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -91,8 +93,11 @@ assert.strictEqual(dest.listeners('finish').length, 0); console.error(src._readableState); process.on('exit', function () { - src._readableState.buffer.length = 0; + src.readableBuffer.length = 0; console.error(src._readableState); - assert(src._readableState.length >= src.readableHighWaterMark); - console.log('ok'); + assert(src.readableLength >= src.readableHighWaterMark); + require('tap').pass(); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream2-writable.js b/test/parallel/test-stream2-writable.js index d5d23d28bb..43b173b784 100644 --- a/test/parallel/test-stream2-writable.js +++ b/test/parallel/test-stream2-writable.js @@ -1,3 +1,5 @@ +'use strict'; + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } @@ -125,7 +127,7 @@ for (var i = 0; i < chunks.length; i++) { } while (ret !== false && _i2 < chunks.length); if (_i2 < chunks.length) { - assert(_tw2._writableState.length >= 50); + assert(_tw2.writableLength >= 50); _tw2.once('drain', W); } else { _tw2.end(); @@ -388,4 +390,7 @@ function forEach(xs, f) { for (var i = 0, l = xs.length; i < l; i++) { f(xs[i], i); } -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-stream3-cork-end.js b/test/parallel/test-stream3-cork-end.js index 8e3605ccfa..8e306f2732 100644 --- a/test/parallel/test-stream3-cork-end.js +++ b/test/parallel/test-stream3-cork-end.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -6,7 +8,7 @@ var assert = require('assert/'); var stream = require('../../'); var Writable = stream.Writable; -// Test the buffering behaviour of Writable streams. +// Test the buffering behavior of Writable streams. // // The call to cork() triggers storing chunks which are flushed // on calling end() and the stream subsequently ended. @@ -90,4 +92,7 @@ writeChunks(inputChunks, function () { // stream should have ended in next tick assert.ok(seenEnd); }); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream3-cork-uncork.js b/test/parallel/test-stream3-cork-uncork.js index d80e7645e1..779773d5b3 100644 --- a/test/parallel/test-stream3-cork-uncork.js +++ b/test/parallel/test-stream3-cork-uncork.js @@ -1,3 +1,5 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ @@ -6,7 +8,7 @@ var assert = require('assert/'); var stream = require('../../'); var Writable = stream.Writable; -// Test the buffering behaviour of Writable streams. +// Test the buffering behavior of Writable streams. // // The call to cork() triggers storing chunks which are flushed // on calling uncork() in the same tick. @@ -67,7 +69,7 @@ writeChunks(inputChunks, function () { // trigger writing out the buffer w.uncork(); - // buffered bytes shoud be seen in current tick + // buffered bytes should be seen in current tick assert.strictEqual(seenChunks.length, 4); // did the chunks match @@ -85,4 +87,7 @@ writeChunks(inputChunks, function () { // the stream should not have been ended assert.ok(!seenEnd); }); +}); +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); }); \ No newline at end of file diff --git a/test/parallel/test-stream3-pause-then-read.js b/test/parallel/test-stream3-pause-then-read.js index a0269492e4..ed480b2163 100644 --- a/test/parallel/test-stream3-pause-then-read.js +++ b/test/parallel/test-stream3-pause-then-read.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -37,6 +39,7 @@ var expectEndingData = expectTotalData; var r = new Readable({ highWaterMark: 1000 }); var chunks = totalChunks; r._read = function (n) { + console.log('_read called', chunks); if (!(chunks % 2)) setImmediate(push);else if (!(chunks % 3)) process.nextTick(push);else push(); }; @@ -46,6 +49,7 @@ function push() { if (chunk) { totalPushed += chunk.length; } + console.log('chunks', chunks); r.push(chunk); } @@ -61,9 +65,10 @@ function readn(n, then) { expectEndingData -= n; (function read() { var c = r.read(n); + console.error('c', c); if (!c) r.once('readable', read);else { assert.strictEqual(c.length, n); - assert(!r._readableState.flowing); + assert(!r.readableFlowing); then(); } })(); @@ -155,7 +160,10 @@ function pipe() { console.error('written', written, totalPushed); assert.strictEqual(written, expectEndingData); assert.strictEqual(totalPushed, expectTotalData); - console.log('ok'); + require('tap').pass(); }); r.pipe(w); -} \ No newline at end of file +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/parallel/test-streams-highwatermark.js b/test/parallel/test-streams-highwatermark.js index 789af9448b..f3d8a4ed1e 100644 --- a/test/parallel/test-streams-highwatermark.js +++ b/test/parallel/test-streams-highwatermark.js @@ -1,20 +1,77 @@ +'use strict'; + /**/ var bufferShim = require('safe-buffer').Buffer; /**/ -require('../common'); - -// This test ensures that the stream implementation correctly handles values -// for highWaterMark which exceed the range of signed 32 bit integers. +var common = require('../common'); var assert = require('assert/'); var stream = require('../../'); -// This number exceeds the range of 32 bit integer arithmetic but should still -// be handled correctly. -var ovfl = Number.MAX_SAFE_INTEGER; +{ + // This test ensures that the stream implementation correctly handles values + // for highWaterMark which exceed the range of signed 32 bit integers and + // rejects invalid values. + + // This number exceeds the range of 32 bit integer arithmetic but should still + // be handled correctly. + var ovfl = Number.MAX_SAFE_INTEGER; + + var readable = stream.Readable({ highWaterMark: ovfl }); + assert.strictEqual(readable._readableState.highWaterMark, ovfl); + + var writable = stream.Writable({ highWaterMark: ovfl }); + assert.strictEqual(writable._writableState.highWaterMark, ovfl); + + var _loop = function (invalidHwm) { + var _loop2 = function (type) { + common.expectsError(function () { + type({ highWaterMark: invalidHwm }); + }, { + type: TypeError, + code: 'ERR_INVALID_OPT_VALUE', + message: 'The value "' + invalidHwm + '" is invalid for option "highWaterMark"' + }); + }; + + var _arr2 = [stream.Readable, stream.Writable]; + + for (var _i2 = 0; _i2 < _arr2.length; _i2++) { + var type = _arr2[_i2]; + _loop2(type); + } + }; + + var _arr = [true, false, '5', {}, -5, NaN]; + for (var _i = 0; _i < _arr.length; _i++) { + var invalidHwm = _arr[_i]; + _loop(invalidHwm); + } +} + +{ + // This test ensures that the push method's implementation + // correctly handles the edge case where the highWaterMark and + // the state.length are both zero + + var _readable = stream.Readable({ highWaterMark: 0 }); + + for (var i = 0; i < 3; i++) { + var needMoreData = _readable.push(); + assert.strictEqual(needMoreData, true); + } +} + +{ + // This test ensures that the read(n) method's implementation + // correctly handles the edge case where the highWaterMark, state.length + // and n are all zero -var readable = stream.Readable({ highWaterMark: ovfl }); -assert.strictEqual(readable._readableState.highWaterMark, ovfl); + var _readable2 = stream.Readable({ highWaterMark: 0 }); -var writable = stream.Writable({ highWaterMark: ovfl }); -assert.strictEqual(writable._writableState.highWaterMark, ovfl); \ No newline at end of file + _readable2._read = common.mustCall(); + _readable2.read(0); +} +;require('tap').pass('sync run');var _list = process.listeners('uncaughtException');process.removeAllListeners('uncaughtException');_list.pop();_list.forEach(function (e) { + return process.on('uncaughtException', e); +}); \ No newline at end of file diff --git a/test/verify-dependencies.js b/test/verify-dependencies.js deleted file mode 100644 index e7fba50f1f..0000000000 --- a/test/verify-dependencies.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict' - -var pack = require('../package.json'); -var assert = require('assert'); - -function verifyNoCaret(deps) { - var keys = Object.keys(deps); - for (var i = 0; i < keys.length; i++) { - assert(deps[keys[i]][0] !== '^', keys[i] + ' must not be depended on using ^') - } -} - -verifyNoCaret(pack.dependencies) diff --git a/transform.js b/transform.js deleted file mode 100644 index b1baba26da..0000000000 --- a/transform.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./readable').Transform diff --git a/writable-browser.js b/writable-browser.js deleted file mode 100644 index ebdde6a85d..0000000000 --- a/writable-browser.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/_stream_writable.js'); diff --git a/writable.js b/writable.js deleted file mode 100644 index 3211a6f80d..0000000000 --- a/writable.js +++ /dev/null @@ -1,8 +0,0 @@ -var Stream = require("stream") -var Writable = require("./lib/_stream_writable.js") - -if (process.env.READABLE_STREAM === 'disable') { - module.exports = Stream && Stream.Writable || Writable -} else { - module.exports = Writable -}