Skip to content

Commit

Permalink
Better detection of object names
Browse files Browse the repository at this point in the history
Also moved this feature into its own function: _name
  • Loading branch information
felixge committed May 24, 2010
1 parent 5888781 commit 918a40b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 37 deletions.
1 change: 1 addition & 0 deletions Readme.md
Expand Up @@ -9,6 +9,7 @@ A node.js module that helps with mocking and behavior verification.
* Overwrite and mock individual object functions
* Verify that all expected calls have been made in the expected order
* Restore mocked functions to their original behavior
* Detect object / class names from obj.constructor.name and obj.toString()

## Installation

Expand Down
37 changes: 20 additions & 17 deletions lib/gently/gently.js
@@ -1,18 +1,14 @@
var Gently = exports.Gently = function() {
function Gently() {
this.expectations = [];

var self = this;
process.addListener('exit', function() {
self.verify('process exit');
});
};

Gently.prototype.toString = function() {
return '[Gently]';
};
exports.Gently = Gently;

Gently.prototype.expect = function(obj, method, count, mock) {
var name;
if (typeof obj == 'function') {
// expect(mock) interface
mock = obj;
Expand All @@ -34,16 +30,7 @@ Gently.prototype.expect = function(obj, method, count, mock) {
count = 1;
}

if (obj) {
name = obj.toString()+'.'+method+'()';
} else {
if (mock.name) {
name = mock.name+'()';
} else {
name = '>> '+mock.toString()+' <<';
}
}

var name = this._name(obj, method, mock);
while (count-- > 0) {
this.expectations.push({obj: obj, method: method, mock: mock, name: name});
}
Expand All @@ -64,7 +51,7 @@ Gently.prototype.expect = function(obj, method, count, mock) {

Gently.prototype.restore = function(obj, method) {
if (!obj[method] || !obj[method]._original) {
throw new Error(obj.toString()+'.'+method+'() is not gently mocked');
throw new Error(this._name(obj, method)+' is not gently mocked');
}
obj[method] = obj[method]._original;
};
Expand Down Expand Up @@ -98,4 +85,20 @@ Gently.prototype._mock = function(self, obj, method, name, args) {
if (expectation.mock) {
return expectation.mock.apply(self, args);
}
};

Gently.prototype._name = function(obj, method, mock) {
if (obj) {
var objectName = obj.toString();
if (objectName == '[object Object]' && obj.constructor.name) {
objectName = '['+obj.constructor.name+']';
}
return (objectName)+'.'+method+'()';
}

if (mock.name) {
return mock.name+'()';
}

return '>> '+mock.toString()+' <<';
};
74 changes: 54 additions & 20 deletions test/simple/test-gently.js
Expand Up @@ -10,18 +10,19 @@ function test(test) {

test(function constructor() {
assert.deepEqual(gently.expectations, []);
});

test(function toString() {
assert.deepEqual(gently.toString(), '[Gently]');
assert.equal(gently.constructor.name, 'Gently');
});

test(function expectObjMethod() {
var OBJ = {};
var OBJ = {}, NAME = 'foobar';
OBJ.foo = function(x) {
return x;
};

gently._name = function() {
return NAME;
};

var original = OBJ.foo
, mock = function() {};

Expand All @@ -34,7 +35,7 @@ test(function expectObjMethod() {
assert.strictEqual(expectation.obj, OBJ);
assert.strictEqual(expectation.method, 'foo');
assert.strictEqual(expectation.mock, mock);
assert.strictEqual(expectation.name, OBJ.toString()+'.foo()');
assert.strictEqual(expectation.name, NAME);
assert.strictEqual(OBJ.foo._original, original);
})();

Expand All @@ -54,7 +55,7 @@ test(function expectObjMethod() {
assert.strictEqual(self, SELF);
assert.strictEqual(obj, OBJ);
assert.strictEqual(method, 'foo');
assert.strictEqual(name, gently.expectations[0].name);
assert.strictEqual(name, NAME);
assert.deepEqual(args, [1, 2]);
return 23;
};
Expand All @@ -63,43 +64,43 @@ test(function expectObjMethod() {
});

test(function expectClosure() {
function closureFn() {}
var NAME = 'MY CLOSURE';
function closureFn() {};

gently._name = function() {
return NAME;
};

var fn = gently.expect(closureFn);
assert.equal(gently.expectations.length, 1);
var expectation = gently.expectations[0];
assert.strictEqual(expectation.obj, null);
assert.strictEqual(expectation.method, null);
assert.strictEqual(expectation.mock, closureFn);
assert.strictEqual(expectation.name, 'closureFn()');
assert.strictEqual(expectation.name, NAME);

var mockCalled = 0, SELF = {};
gently._mock = function(self, obj, method, name, args) {
mockCalled++;
assert.strictEqual(self, SELF);
assert.strictEqual(obj, null);
assert.strictEqual(method, null);
assert.strictEqual(name, 'closureFn()');
assert.strictEqual(name, NAME);
assert.deepEqual(args, [1, 2]);
return 23;
};
assert.equal(fn.apply(SELF, [1, 2]), 23);
assert.equal(mockCalled, 1);

var noName = function() {return a+a};
gently.expect(2, noName);
assert.equal(gently.expectations.length, 3);
assert.equal(gently.expectations[1].name, '>> '+noName.toString()+' <<');
});

test(function restore() {
var OBJ = {};
var OBJ = {}, NAME = '[my object].myFn()';
OBJ.foo = function(x) {
return x;
};

OBJ.toString = function() {
return '[my object]';
gently._name = function() {
return NAME;
};

var original = OBJ.foo;
Expand All @@ -112,7 +113,7 @@ test(function restore() {
gently.restore(OBJ, 'foo');
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, '[my object].foo() is not gently mocked');
assert.equal(e.message, NAME+' is not gently mocked');
}
})();
});
Expand Down Expand Up @@ -144,7 +145,7 @@ test(function mock() {
gently._mock(SELF, OBJ1, 'foo', 'dummy_name', [5]);
assert.ok(false, 'throw needs to happen');
} catch (e) {
assert.equal(e.message, 'Unexpected call to dummy_name, expected call to [OBJ 2].bar()');
assert.equal(e.message, 'Unexpected call to dummy_name, expected call to '+gently._name(OBJ2, 'bar'));
}

assert.equal(gently.expectations.length, 1);
Expand Down Expand Up @@ -185,4 +186,37 @@ test(function processExit() {

process.emit('exit');
assert.equal(verifyCalled, 1);
});

test(function _name() {
(function testNamedClass() {
function Foo() {};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), '[Foo].bar()');
})();

(function testToStringPreference() {
function Foo() {};
Foo.prototype.toString = function() {
return '[Superman 123]';
};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), '[Superman 123].bar()');
})();

(function testUnamedClass() {
var Foo = function() {};
var foo = new Foo();
assert.equal(gently._name(foo, 'bar'), foo.toString()+'.bar()');
})();

(function testNamedClosure() {
function myClosure() {};
assert.equal(gently._name(null, null, myClosure), myClosure.name+'()');
})();

(function testUnamedClosure() {
var myClosure = function() {2+2 == 5};
assert.equal(gently._name(null, null, myClosure), '>> '+myClosure.toString()+' <<');
})();
});

0 comments on commit 918a40b

Please sign in to comment.