Skip to content

Commit

Permalink
Merge pull request #35 from cloudkick/spyon
Browse files Browse the repository at this point in the history
A spyOn implementation for whiskey. (in progress)
  • Loading branch information
Kami committed May 11, 2012
2 parents 5ec13a7 + d559765 commit 0a801c3
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 1 deletion.
129 changes: 129 additions & 0 deletions example/test-spyon.js
@@ -0,0 +1,129 @@
/*
* Licensed to Cloudkick, Inc ('Cloudkick') under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Cloudkick licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* @constructor
*/
function Foo () {
/**
* @param {bool}
*/
this.fooCalled = false;
/**
* @param {string}
*/
this.bar = "";
/**
* @param {string}
*/
this.postFix = 'postFix';
}

Foo.prototype.setFoo = function () {
this.fooCalled = true;
};

/**
* @param {string} bar
*/
Foo.prototype.setBar = function (bar) {
this.bar = bar;
return bar + this.postFix;
};

exports['test_spyon_calls_method'] = function(test, assert) {
var foo = new Foo();
test.spy.on('setFoo', foo);
foo.setFoo();
assert.equal(foo.fooCalled, true);
test.spy.clear('setFoo', foo);
test.finish();
};

exports['test_spyon_returns_right'] = function(test, assert) {
var foo, str;
foo = new Foo();
str = 'foo';
test.spy.on('setBar', foo);
assert.equal(foo.setBar(str), str + foo.postFix);
test.spy.clear('setBar', foo);
test.finish();
};

exports['test_spyon_count_correct'] = function (test, assert) {
var foo = new Foo();
test.spy.on('setFoo', foo);
foo.setFoo();
foo.setFoo();
foo.setFoo();
foo.setFoo();
foo.setFoo();
foo.setFoo();
foo.setFoo();
assert.equal(test.spy.called('setFoo'), 7);
test.spy.clear('setFoo', foo);
test.finish();
};


exports['test_spyon_accepts_function'] = function (test, assert) {
var foo, func, set;
foo = new Foo();
set = false;
func = function () {
set = true;
}
test.spy.on('setFoo', foo, func);
foo.setFoo();
assert.equal(set, true);
test.spy.clear('setFoo', foo);
test.finish();
};

exports['test_spyon_reapplies_original_function'] = function (test, assert) {
var foo, func;
foo = new Foo();
func = foo.setFoo;
test.spy.on('setFoo', foo);
test.spy.clear('setFoo', foo);
assert.equal(foo.setFoo, func);
test.finish();
};

exports['test_spyon_reapplies_given_function'] = function (test, assert) {
var foo, func, set;
foo = new Foo();
set = false;
func = function () {
set = true;
};
test.spy.on('setFoo', foo);
test.spy.clear('setFoo', foo, func);
assert.equal(foo.setFoo, func);
test.finish();
};

exports['test_spyon_reset'] = function(test, assert) {
var foo = new Foo();
test.spy.on('setFoo', foo);
foo.setFoo();
test.spy.reset('setFoo');
assert.equal(test.spy.called('setFoo'), 0);
test.spy.clear('setFoo', foo);
test.finish();
};

78 changes: 78 additions & 0 deletions lib/common.js
Expand Up @@ -199,6 +199,7 @@ Test.prototype._getTestObject = function(finishFunc) {

testObj.finish = finishFunc;
testObj.skip = skipFunc;
testObj.spy = new SpyOn();

return testObj;
};
Expand Down Expand Up @@ -544,3 +545,80 @@ exports.TestFile = TestFile;
exports.getTestFilePathAndPattern = getTestFilePathAndPattern;

exports.registerCustomAssertionFunctions = registerCustomAssertionFunctions;

/**
* @constructor
*/
function SpyOn (){
/**
* This tracks the number of times a function has been fired.
* @param {Object.<number>}
* @private
*/
this._callCount = {};
/**
* This tracks the function to call
* @param {Object.<Function>}
* @private
*/
this._funcMap = {};
};

/**
* @param {string} funcName The key to use for tracking call counts.
* @param {Object} context The context in which the function should execute.
* @param {Function} optFunc The optional function to call in wrapper. If not
* provided, original function will be called.
*/
SpyOn.prototype.on = function (funcName, context, optFunc) {
var wrapper, func;
if (optFunc) {
func = optFunc;
} else {
func = context[funcName];
}
if (this._callCount.hasOwnProperty(funcName)) {
throw "Function already being tracked.";
}
this.reset(funcName);
wrapper = (function () {
this._callCount[funcName] += 1;
return func.apply(context, arguments);
}).bind(this);
context[funcName] = wrapper;
this._funcMap[funcName] = func;
return this;
};

/**
* @param {string} funcName The key to clear.
* @param {Object} context The context in which the function should execute.
* @param {Function} optFunc The optional function to reapply to the context.
*/
SpyOn.prototype.clear = function (funcName, context, optFunc) {
if (optFunc) {
context[funcName] = optFunc
} else {
context[funcName] = this._funcMap[funcName];
}
delete this._callCount[funcName];
delete this._funcMap[funcName];
return this;
};

/**
* Reset a call count.
* @param {string} funcName The name of the function.
*/
SpyOn.prototype.reset = function (funcName) {
this._callCount[funcName] = 0;
};

/**
* Get the call count for a spied on function.
* @param {string} funcName
*/
SpyOn.prototype.called = function (funcName) {
return this._callCount[funcName];
};

2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "whiskey",
"description": "A simple test runner for NodeJS applications.",
"version": "0.6.9",
"version": "0.6.10",
"author": "Cloudkick, Inc. <tomaz+npm@cloudkick.com> http://www.cloudkick.com",
"keywords": [ "whiskey", "tests", "test runner", "testing", "tdd", "coverage", "test coverage"],
"homepage": "https://github.com/cloudkick/whiskey",
Expand Down
8 changes: 8 additions & 0 deletions test/run.sh
Expand Up @@ -260,6 +260,14 @@ if [ $? -ne 0 ]; then
exit 1
fi

"${CWD}/bin/whiskey" --timeout 1000 \
--tests "${CWD}/example/test-spyon.js"

if [ $? -ne 0 ]; then
echo "Test didn't exit with zero exit code."
exit 1
fi

echo ""
echo "* * * Whiskey test suite PASSED. * * *"
exit 0

0 comments on commit 0a801c3

Please sign in to comment.