From 8e60dcbbb0724fb5fbaacbfb521356e6d268d42c Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 4 Jan 2021 12:01:45 -0800 Subject: [PATCH] [Robustness] cache and call-bind more prototype methods --- lib/results.js | 14 +++++++++----- lib/test.js | 27 ++++++++++++++++----------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/results.js b/lib/results.js index e07ac0d9..37bb1917 100644 --- a/lib/results.js +++ b/lib/results.js @@ -9,6 +9,10 @@ var inspect = require('object-inspect'); var callBound = require('call-bind/callBound'); var has = require('has'); var regexpTest = callBound('RegExp.prototype.test'); +var $split = callBound('String.prototype.split'); +var $replace = callBound('String.prototype.replace'); +var $shift = callBound('Array.prototype.shift'); +var $push = callBound('Array.prototype.push'); var yamlIndicators = /:|-|\?/; var nextTick = typeof setImmediate !== 'undefined' ? setImmediate @@ -19,7 +23,7 @@ module.exports = Results; inherits(Results, EventEmitter); function coalesceWhiteSpaces(str) { - return String(str).replace(/\s+/g, ' '); + return $replace(String(str), /\s+/g, ' '); } function Results() { @@ -94,7 +98,7 @@ Results.prototype.createStream = function (opts) { Results.prototype.push = function (t) { var self = this; - self.tests.push(t); + $push(self.tests, t); self._watch(t); self.emit('_push', t); }; @@ -186,7 +190,7 @@ function encodeResult(res, count) { var errorStack = res.error && res.error.stack; var stack = defined(actualStack, errorStack); if (stack) { - var lines = String(stack).split('\n'); + var lines = $split(String(stack), '\n'); output += inner + 'stack: |-\n'; for (var i = 0; i < lines.length; i++) { output += inner + ' ' + lines[i] + '\n'; @@ -199,11 +203,11 @@ function encodeResult(res, count) { function getNextTest(results) { if (!results._only) { - return results.tests.shift(); + return $shift(results.tests); } do { - var t = results.tests.shift(); + var t = $shift(results.tests); if (!t) continue; if (results._only === t) { return t; diff --git a/lib/test.js b/lib/test.js index 12065092..06ff1b17 100644 --- a/lib/test.js +++ b/lib/test.js @@ -17,6 +17,11 @@ var toLowerCase = callBound('String.prototype.toLowerCase'); var isProto = callBound('Object.prototype.isPrototypeOf'); var $test = callBound('RegExp.prototype.test'); var objectToString = callBound('Object.prototype.toString'); +var $split = callBound('String.prototype.split'); +var $replace = callBound('String.prototype.replace'); +var $strSlice = callBound('String.prototype.slice'); +var $push = callBound('Array.prototype.push'); +var $shift = callBound('Array.prototype.shift'); module.exports = Test; @@ -128,7 +133,7 @@ Test.prototype.run = function () { Test.prototype.test = function (name, opts, cb) { var self = this; var t = new Test(name, opts, cb); - this._progeny.push(t); + $push(this._progeny, t); this.pendingCount++; this.emit('test', t); t.on('prerun', function () { @@ -150,8 +155,8 @@ Test.prototype.test = function (name, opts, cb) { Test.prototype.comment = function (msg) { var that = this; - forEach(trim(msg).split('\n'), function (aMsg) { - that.emit('result', trim(aMsg).replace(/^#\s*/, '')); + forEach($split(trim(msg), '\n'), function (aMsg) { + that.emit('result', $replace(trim(aMsg), /^#\s*/, '')); }); }; @@ -191,7 +196,7 @@ Test.prototype._end = function (err) { if (!this._cb && !this._todo && !this._skip) this.fail('# TODO ' + this.name); if (this._progeny.length) { - var t = this._progeny.shift(); + var t = $shift(this._progeny); t.on('end', function () { self._end(); }); t.run(); return; @@ -266,7 +271,7 @@ Test.prototype._assert = function assert(ok, opts) { if (!ok) { var e = new Error('exception'); - var err = (e.stack || '').split('\n'); + var err = $split(e.stack || '', '\n'); var dir = __dirname + path.sep; for (var i = 0; i < err.length; i++) { @@ -306,7 +311,7 @@ Test.prototype._assert = function assert(ok, opts) { /((?:\/|[a-zA-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)\)?/ */ var re = /^(?:[^\s]*\s*\bat\s+)(?:(.*)\s+\()?((?:\/|[a-zA-Z]:\\)[^:)]+:(\d+)(?::(\d+))?)\)?$/; - var lineWithTokens = err[i].replace(process.cwd(), '/$CWD').replace(__dirname, '/$TEST'); + var lineWithTokens = $replace($replace(err[i], process.cwd(), '/$CWD'), __dirname, '/$TEST'); var m = re.exec(lineWithTokens); if (!m) { @@ -314,15 +319,15 @@ Test.prototype._assert = function assert(ok, opts) { } var callDescription = m[1] || ''; - var filePath = m[2].replace('/$CWD', process.cwd()).replace('/$TEST', __dirname); + var filePath = $replace($replace(m[2], '/$CWD', process.cwd()), '/$TEST', __dirname); - if (filePath.slice(0, dir.length) === dir) { + if ($strSlice(filePath, 0, dir.length) === dir) { continue; } // Function call description may not (just) be a function name. // Try to extract function name by looking at first "word" only. - res.functionName = callDescription.split(/\s+/)[0]; + res.functionName = $split(callDescription, /\s+/)[0]; res.file = filePath; res.line = Number(m[3]); if (m[4]) res.column = Number(m[4]); @@ -610,12 +615,12 @@ Test.prototype['throws'] = function (fn, expected, msg, extra) { var keys = Object.keys(expected); // Special handle errors to make sure the name and the message are compared as well. if (expected instanceof Error) { - keys.push('name', 'message'); + $push(keys, 'name', 'message'); } else if (keys.length === 0) { throw new TypeError('`throws` validation object must not be empty'); } passed = keys.every(function (key) { - if (typeof caught.error[key] === 'string' && isRegExp(expected[key]) && expected[key].test(caught.error[key])) { + if (typeof caught.error[key] === 'string' && isRegExp(expected[key]) && $test(expected[key], caught.error[key])) { return true; } if (key in caught.error && deepEqual(caught.error[key], expected[key], { strict: true })) {