Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add massUnwrap #5

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,9 @@ A convenience function for restoring the function back the way it was before
you started. Won't unwrap if somebody else has monkeypatched the function after
you (but will log in that case). Won't throw if you try to double-unwrap a
function (but will log).

#### shimmer.massUnwrap(nodules, names)

Just like `unwrap`, with the addition that you can unwrap multiple methods on
multiple modules. Note that this function expects the list of functions to be
unwrapped on all of the modules to be the same.
22 changes: 22 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,30 @@ function unwrap (nodule, name) {
}
}

function massUnwrap (nodules, names) {
if (!nodules) {
logger('must provide one or more modules to patch')
logger((new Error()).stack)
return
} else if (!Array.isArray(nodules)) {
nodules = [nodules]
}

if (!(names && Array.isArray(names))) {
logger('must provide one or more functions to unwrap on modules')
return
}

nodules.forEach(function (nodule) {
names.forEach(function (name) {
unwrap(nodule, name)
})
})
}

shimmer.wrap = wrap
shimmer.massWrap = massWrap
shimmer.unwrap = unwrap
shimmer.massUnwrap = massUnwrap

module.exports = shimmer
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Safe(r) monkeypatching for JavaScript.",
"main": "index.js",
"scripts": {
"test": "standard && tap test/*.tap.js --coverage"
"test": "tap test/*.tap.js --coverage"
},
"repository": {
"type": "git",
Expand Down
121 changes: 121 additions & 0 deletions test/massUnwrap.tap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use strict'

var tap = require('tap')
var test = tap.test
var sinon = require('sinon')
var shimmer = require('../index.js')

var outsider = 0
function counter () { return ++outsider }
function anticounter () { return --outsider }

var generator = {
inc: counter,
dec: anticounter
}

test('should unwrap safely', function (t) {
t.plan(18)

t.equal(counter, generator.inc, 'basic function equality testing should work')
t.equal(anticounter, generator.dec, 'basic function equality testing should work')
t.doesNotThrow(function () { generator.inc() })
t.equal(1, outsider, 'calls have side effects')
t.doesNotThrow(function () { generator.dec() })
t.equal(0, outsider, 'calls have side effects')

function wrapper (original) {
return function () {
return original.apply(this, arguments)
}
}
shimmer.massWrap(generator, ['inc', 'dec'], wrapper)

t.doesNotEqual(counter, generator.inc, 'function should be wrapped')
t.doesNotEqual(anticounter, generator.dec, 'function should be wrapped')

t.doesNotThrow(function () { generator.inc() })
t.equal(1, outsider, 'original function has still been called')
t.doesNotThrow(function () { generator.dec() })
t.equal(0, outsider, 'original function has still been called')

shimmer.massUnwrap(generator, ['inc', 'dec'])
t.equal(counter, generator.inc, 'basic function equality testing should work')
t.equal(anticounter, generator.dec, 'basic function equality testing should work')

t.doesNotThrow(function () { generator.inc() })
t.equal(1, outsider, 'original function has still been called')
t.doesNotThrow(function () { generator.dec() })
t.equal(0, outsider, 'original function has still been called')
})

test("shouldn't throw on double unwrapping", function (t) {
t.plan(10)

t.equal(counter, generator.inc, 'basic function equality testing should work')
t.equal(anticounter, generator.dec, 'basic function equality testing should work')

var mock = sinon.stub()
shimmer({logger: mock})

function wrapper (original) {
return function () {
return original.apply(this, arguments)
}
}
shimmer.wrap(generator, 'inc', wrapper)
shimmer.wrap(generator, 'dec', wrapper)

t.doesNotEqual(counter, generator.inc, 'function should be wrapped')
t.doesNotEqual(anticounter, generator.dec, 'function should be wrapped')

shimmer.massUnwrap(generator, ['inc', 'dec'])
t.equal(counter, generator.inc, 'basic function equality testing should work')
t.equal(anticounter, generator.dec, 'basic function equality testing should work')

t.doesNotThrow(function () { shimmer.massUnwrap(generator, ['inc', 'dec']) },
'should double unwrap without issue')
t.equal(counter, generator.inc, 'function is unchanged after unwrapping')
t.equal(anticounter, generator.dec, 'function is unchanged after unwrapping')

t.doesNotThrow(function () {
sinon.assert.calledWith(mock, 'no original to unwrap to -- ' +
'has inc already been unwrapped?')
sinon.assert.calledWith(mock, 'no original to unwrap to -- ' +
'has dec already been unwrapped?')
sinon.assert.calledTwice(mock)
}, 'logger was called with the expected message')
})

test('massUnwrap called with no arguments', function (t) {
t.plan(2)

var mock = sinon.expectation
.create('logger')
.twice()
shimmer({logger: mock})

t.doesNotThrow(function () { shimmer.massUnwrap() }, 'should log instead of throwing')

t.doesNotThrow(function () {
mock.verify()
}, 'logger was called with the expected message')
})

test('massUnwrap called with module but nothing else', function (t) {
t.plan(2)

var mock = sinon.expectation
.create('logger')
.withExactArgs('must provide one or more functions to unwrap on modules')
.once()
shimmer({logger: mock})

t.doesNotThrow(function () {
shimmer.massUnwrap(generator)
}, "wrapping with only 1 argument doesn't throw")

t.doesNotThrow(function () {
mock.verify()
}, 'logger was called with the expected message')
})