Skip to content

Commit 0feec9f

Browse files
cjohansenChristian Johansen
authored and
Christian Johansen
committed
Initial commit of sinon test spy/stubbing/mocking library
0 parents  commit 0feec9f

File tree

8 files changed

+860
-0
lines changed

8 files changed

+860
-0
lines changed

jsTestDriver.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
server: http://localhost:4224
2+
3+
load:
4+
- lib/*.js
5+
- src/sinon.js
6+
- src/spy.js
7+
- src/*.js
8+
- test/*.js

lib/object.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
(function () {
2+
var isOwnProperty = (function () {
3+
var hasOwn = Object.prototype.hasOwnProperty;
4+
5+
if (typeof hasOwn == "function" && Function.prototype.call) {
6+
return function (object, property) {
7+
return hasOwn.call(object, property);
8+
};
9+
} else {
10+
return function (object, property) {
11+
var value = object[property];
12+
13+
if (typeof value == "undefined") {
14+
return false;
15+
}
16+
17+
return Object.prototype[property] !== value;
18+
};
19+
}
20+
}());
21+
22+
if (!Object.each) {
23+
Object.each = (function () {
24+
// Troublesome object properties
25+
var oDontEnums = ["toString", "toLocaleString", "valueOf",
26+
"hasOwnProperty", "isPrototypeOf",
27+
"constructor", "propertyIsEnumerable"];
28+
29+
// Troublesome function properties
30+
var fDontEnums = ["call", "apply", "prototype"];
31+
fDontEnums = oDontEnums.concat(fDontEnums);
32+
33+
var needsFix = true;
34+
var object = { toString: 1 };
35+
36+
// If we can loop this property, we don't need the fix
37+
// This test is only performed once - when the function is
38+
// defined
39+
for (var prop in object) {
40+
if (isOwnProperty(object, prop)) {
41+
needsFix = false;
42+
}
43+
}
44+
45+
// The each function
46+
return function (object, callback) {
47+
if (typeof callback != "function") {
48+
throw new TypeError("Please provide a callback");
49+
}
50+
51+
if (!object) {
52+
return;
53+
}
54+
55+
// Normal loop, should expose all enumerable properties
56+
// in conforming browsers
57+
for (var prop in object) {
58+
if (isOwnProperty(object, prop)) {
59+
callback(prop, object[prop]);
60+
}
61+
}
62+
63+
// Internet Explorer
64+
if (needsFix) {
65+
var properties = typeof object == "function" ?
66+
fDontEnums : oDontEnums;
67+
var property;
68+
69+
for (var i = 0, l = properties.length; i < l; i++) {
70+
property = properties[i];
71+
72+
if (isOwnProperty(object, property)) {
73+
callback(property, object[property]);
74+
}
75+
}
76+
}
77+
}
78+
}());
79+
}
80+
81+
if (!Object.extend) {
82+
Object.extend = (function () {
83+
function extend (target, source) {
84+
target = target || {};
85+
86+
if (!source) {
87+
return target;
88+
}
89+
90+
Object.each(source, function (prop, val) {
91+
target[prop] = val;
92+
});
93+
94+
return target;
95+
}
96+
97+
return extend;
98+
}());
99+
}
100+
101+
if (!Object.create) {
102+
Object.create = function (object) {
103+
function F () {};
104+
F.prototype = object;
105+
106+
return new F;
107+
};
108+
}
109+
}());

src/sinon.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var sinon = (function () {
2+
return {};
3+
}());

src/spy.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
(function () {
2+
function spy (func) {
3+
return spy.create(func);
4+
}
5+
6+
Object.extend(spy, (function () {
7+
function create (func) {
8+
if (typeof func != "function") {
9+
throw new TypeError("spy needs a function to spy on");
10+
}
11+
12+
function proxy () {
13+
return proxy.invoke(func, this, arguments);
14+
}
15+
16+
Object.extend(proxy, spy);
17+
delete proxy.create;
18+
Object.extend(proxy, func);
19+
20+
return proxy;
21+
}
22+
23+
function invoke (func, thisObj, args) {
24+
if (!this.calls) {
25+
this.calls = [];
26+
}
27+
28+
var call = spyCall.create(thisObj, args);
29+
30+
try {
31+
call.returnValue = func.apply(thisObj, args);
32+
} catch (e) {
33+
call.exception = e;
34+
throw e;
35+
} finally {
36+
this.calls.push(call);
37+
}
38+
39+
return call.returnValue;
40+
}
41+
42+
function getCall (i) {
43+
return this.calls && this.calls[i];
44+
}
45+
46+
function called () {
47+
return this.callCount() > 0;
48+
}
49+
50+
function callCount () {
51+
return this.calls && this.calls.length;
52+
}
53+
54+
function calledOn (thisObj) {
55+
return matchAnyCall(this, "calledOn", arguments);
56+
}
57+
58+
function calledWith () {
59+
return matchAnyCall(this, "calledWith", arguments);
60+
}
61+
62+
function calledWithExactly () {
63+
return matchAnyCall(this, "calledWithExactly", arguments);
64+
}
65+
66+
function threw (error) {
67+
return matchAnyCall(this, "threw", arguments);
68+
}
69+
70+
function matchAnyCall (proxy, method, args) {
71+
if (!proxy.calls) {
72+
return false;
73+
}
74+
75+
var spyCall;
76+
77+
for (var i = 0, l = proxy.calls.length; i < l; i++) {
78+
spyCall = proxy.calls[i];
79+
80+
if (spyCall[method].apply(spyCall, args)) {
81+
return true;
82+
}
83+
}
84+
85+
return false;
86+
}
87+
88+
return {
89+
create: create,
90+
called: called,
91+
calledOn: calledOn,
92+
calledWith: calledWith,
93+
calledWithExactly: calledWithExactly,
94+
callCount: callCount,
95+
getCall: getCall,
96+
invoke: invoke,
97+
threw: threw
98+
};
99+
}()));
100+
101+
var spyCall = (function () {
102+
function calledOn (thisObj) {
103+
return this.thisObj === thisObj;
104+
}
105+
106+
function calledWith () {
107+
for (var i = 0, l = arguments.length; i < l; i++) {
108+
if (arguments[i] !== this.args[i]) {
109+
return false;
110+
}
111+
}
112+
113+
return true;
114+
}
115+
116+
function calledWithExactly () {
117+
return arguments.length == this.args.length &&
118+
this.calledWith.apply(this, arguments);
119+
}
120+
121+
function returned (value) {
122+
return this.returnValue === value;
123+
}
124+
125+
function threw (error) {
126+
if (typeof error == "undefined" || !this.exception) {
127+
return !!this.exception;
128+
}
129+
130+
if (typeof error == "string") {
131+
return this.exception.name == error;
132+
}
133+
134+
return this.exception === error;
135+
}
136+
137+
function create (thisObj, args, returnValue) {
138+
var proxyCall = Object.create(spyCall);
139+
delete proxyCall.create;
140+
proxyCall.thisObj = thisObj;
141+
proxyCall.args = args;
142+
proxyCall.returnValue = returnValue;
143+
144+
return proxyCall;
145+
}
146+
147+
return {
148+
create: create,
149+
calledOn: calledOn,
150+
calledWith: calledWith,
151+
calledWithExactly: calledWithExactly,
152+
returned: returned,
153+
threw: threw
154+
};
155+
}());
156+
157+
if (typeof sinon != "undefined") {
158+
sinon.spy = spy;
159+
sinon.spyCall = spyCall;
160+
}
161+
}());

src/stub.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
(function () {
2+
function stub (object, property, func) {
3+
if (!object) {
4+
throw new TypeError("Should stub property of object");
5+
}
6+
7+
if (!!func && typeof func != "function") {
8+
throw new TypeError("Custom stub should be function");
9+
}
10+
11+
var method = object[property];
12+
var type = typeof method;
13+
14+
if (!!method && type != "function") {
15+
throw new TypeError("Attempted to stub " + type + " as function");
16+
}
17+
18+
if (typeof func == "function") {
19+
object[property] = !!sinon.spy ? sinon.spy(func) : func;
20+
} else {
21+
object[property] = stub.create();
22+
}
23+
24+
object[property].restore = function () {
25+
object[property] = method;
26+
};
27+
28+
return object[property];
29+
}
30+
31+
Object.extend(stub, (function () {
32+
function create () {
33+
function functionStub () {
34+
if (functionStub.exception) {
35+
throw functionStub.exception;
36+
}
37+
38+
return functionStub.returnValue;
39+
}
40+
41+
Object.extend(functionStub, stub);
42+
43+
if (sinon.spy) {
44+
Object.extend(functionStub, sinon.spy);
45+
}
46+
47+
return functionStub;
48+
}
49+
50+
function returns (value) {
51+
this.returnValue = value;
52+
53+
return this;
54+
}
55+
56+
function throws (error, message) {
57+
if (typeof error == "string") {
58+
this.exception = new Error(message);
59+
this.exception.name = error;
60+
} else {
61+
this.exception = error;
62+
}
63+
64+
return this;
65+
}
66+
67+
return {
68+
create: create,
69+
returns: returns,
70+
throws: throws
71+
};
72+
}()));
73+
74+
if (typeof sinon == "object") {
75+
sinon.stub = stub;
76+
}
77+
}());

test/sinon_test.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
TestCase("SinonTest", {
2+
"test sinon should be object": function () {
3+
assertObject(sinon);
4+
}
5+
});

0 commit comments

Comments
 (0)