dripdrop 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +23 -28
- data/VERSION +1 -1
- data/dripdrop.gemspec +25 -3
- data/example/combined.rb +33 -0
- data/example/pubsub.rb +7 -15
- data/example/stats_app/core.rb +113 -0
- data/example/stats_app/public/.sass-cache/b48b4299d80c05f528daf63fe51d85e5e3c10d98/stats.scssc +0 -0
- data/example/stats_app/public/backbone.js +16 -0
- data/example/stats_app/public/build_templates.rb +5 -0
- data/example/stats_app/public/json2.js +482 -0
- data/example/stats_app/public/protovis-r3.2.js +277 -0
- data/example/stats_app/public/stats.css +5 -0
- data/example/stats_app/public/stats.haml +61 -0
- data/example/stats_app/public/stats.html +26 -0
- data/example/stats_app/public/stats.js +113 -0
- data/example/stats_app/public/stats.scss +10 -0
- data/example/stats_app/public/underscore.js +17 -0
- data/example/xreq_xrep.rb +9 -11
- data/js/dripdrop.js +6 -2
- data/lib/dripdrop/handlers/base.rb +18 -0
- data/lib/dripdrop/handlers/http.rb +18 -18
- data/lib/dripdrop/handlers/websockets.rb +33 -26
- data/lib/dripdrop/handlers/zeromq.rb +30 -24
- data/lib/dripdrop/message.rb +5 -0
- data/lib/dripdrop/node/nodelet.rb +29 -0
- data/lib/dripdrop/node.rb +103 -25
- data/spec/gimite-websocket.rb +442 -0
- data/spec/message_spec.rb +5 -0
- data/spec/node/http_spec.rb +2 -8
- data/spec/node/nodelet_spec.rb +57 -0
- data/spec/node/routing_spec.rb +68 -0
- data/spec/node/websocket_spec.rb +88 -0
- data/spec/node/zmq_pushpull_spec.rb +2 -6
- data/spec/node/zmq_xrepxreq_spec.rb +24 -24
- data/spec/node_spec.rb +0 -1
- data/spec/spec_helper.rb +17 -3
- metadata +27 -5
- data/js/jack.js +0 -876
data/js/jack.js
DELETED
@@ -1,876 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
*
|
3
|
-
* JACK :: JavaScript Mocking.
|
4
|
-
* Version: $Id$
|
5
|
-
*
|
6
|
-
*/
|
7
|
-
|
8
|
-
|
9
|
-
function jack() {} // This needs to be here to make error reporting work correctly in IE.
|
10
|
-
|
11
|
-
(function (){ // START HIDING FROM GLOBAL SCOPE
|
12
|
-
/** EXPORT JACK **/
|
13
|
-
window.jack = new Jack();
|
14
|
-
window.jack.matchers = new Matchers();
|
15
|
-
window.jack.util = new Util();
|
16
|
-
window.jack.FunctionSpecification = FunctionSpecification;
|
17
|
-
window.jack.FunctionGrab = FunctionGrab;
|
18
|
-
return;
|
19
|
-
|
20
|
-
|
21
|
-
/**
|
22
|
-
* Constructor for object that will be exposed as the global jack
|
23
|
-
*/
|
24
|
-
function Jack() {
|
25
|
-
var functionGrabs = {};
|
26
|
-
var objectGrabs = {};
|
27
|
-
var environment = new Environment();
|
28
|
-
var reportMessages = [];
|
29
|
-
var currentExpectation = null;
|
30
|
-
var publicApi = createPublicApi();
|
31
|
-
return publicApi;
|
32
|
-
|
33
|
-
function createPublicApi() {
|
34
|
-
var api = jackFunction;
|
35
|
-
api.grab = grab;
|
36
|
-
api.create = create;
|
37
|
-
api.inspect = inspect;
|
38
|
-
api.expect = expect;
|
39
|
-
api.verify = verify;
|
40
|
-
api.report = report;
|
41
|
-
api.reportAll = reportAll;
|
42
|
-
api.env = environment;
|
43
|
-
return api;
|
44
|
-
}
|
45
|
-
function jackFunction(delegate) {
|
46
|
-
before();
|
47
|
-
firstPass(delegate);
|
48
|
-
// secondPass(delegate);
|
49
|
-
after();
|
50
|
-
}
|
51
|
-
function before() {
|
52
|
-
functionGrabs = {};
|
53
|
-
objectGrabs = {};
|
54
|
-
environment.reset();
|
55
|
-
}
|
56
|
-
function firstPass(delegate) {
|
57
|
-
delegate();
|
58
|
-
}
|
59
|
-
function secondPass(delegate) {
|
60
|
-
var oldExpect = publicApi.expect;
|
61
|
-
publicApi.expect = function(name) {
|
62
|
-
var fakeEx = {};
|
63
|
-
var grab = findGrab(name);
|
64
|
-
if(grab._beenThroughSecondPass) {
|
65
|
-
var ex = grab.expect();
|
66
|
-
for(prop in ex) {
|
67
|
-
if(typeof ex[prop] == "function") {
|
68
|
-
fakeEx[prop] = function() { return fakeEx; }
|
69
|
-
}
|
70
|
-
}
|
71
|
-
}
|
72
|
-
grab._beenThroughSecondPass = true;
|
73
|
-
return fakeEx;
|
74
|
-
};
|
75
|
-
var findMore = true;
|
76
|
-
for(var i=0; findMore && i<10; i++) {
|
77
|
-
try {
|
78
|
-
delegate();
|
79
|
-
findMore = false;
|
80
|
-
} catch(exception) {
|
81
|
-
var line = -1;
|
82
|
-
if(exception.lineNumber != null) {
|
83
|
-
line = exception.lineNumber;
|
84
|
-
} else if(exception['opera#sourceloc'] != null) {
|
85
|
-
line = exception['opera#sourceloc'];
|
86
|
-
}
|
87
|
-
currentExpectation._lineNumber = line;
|
88
|
-
}
|
89
|
-
}
|
90
|
-
publicApi.expect = oldExpect;
|
91
|
-
}
|
92
|
-
function after() {
|
93
|
-
var reports = getTextReports();
|
94
|
-
resetGrabs();
|
95
|
-
if(reports.length > 0) {
|
96
|
-
environment.report(reports[0]);
|
97
|
-
}
|
98
|
-
}
|
99
|
-
function getTextReports() {
|
100
|
-
var failedReports = [];
|
101
|
-
for(var name in functionGrabs) {
|
102
|
-
var reports = functionGrabs[name].reportAll(name);
|
103
|
-
for(var i=0; i<reports.length; i++) {
|
104
|
-
if(reports[i].fail) {
|
105
|
-
failedReports.push(reports[i].message);
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
109
|
-
for(var name in objectGrabs) {
|
110
|
-
var reports = objectGrabs[name].report(name);
|
111
|
-
for(var i=0; i<reports.length; i++) {
|
112
|
-
if(reports[i].fail) {
|
113
|
-
failedReports.push(reports[i].message);
|
114
|
-
}
|
115
|
-
}
|
116
|
-
}
|
117
|
-
return failedReports;
|
118
|
-
}
|
119
|
-
function grab() {
|
120
|
-
if("object" == typeof arguments[0] && "string" == typeof arguments[1]) {
|
121
|
-
var parentObject = arguments[0];
|
122
|
-
var name = arguments[1];
|
123
|
-
var fullName = "[local]." + name;
|
124
|
-
return grabFunction(fullName, parentObject[name], parentObject);
|
125
|
-
} else {
|
126
|
-
var grabbed = null;
|
127
|
-
eval("grabbed = " + arguments[0]);
|
128
|
-
if("function" == typeof grabbed) {
|
129
|
-
var functionGrab = grabFunction(arguments[0], grabbed);
|
130
|
-
eval("grabbed = " + arguments[0]);
|
131
|
-
grabObject(arguments[0], grabbed);
|
132
|
-
return functionGrab;
|
133
|
-
} else if("object" == typeof grabbed) {
|
134
|
-
return grabObject(arguments[0], grabbed);
|
135
|
-
}
|
136
|
-
return null;
|
137
|
-
}
|
138
|
-
}
|
139
|
-
function grabFunction(fullName, grabbed, parentObject) {
|
140
|
-
if(parentObject == null) {
|
141
|
-
parentObject = window;
|
142
|
-
}
|
143
|
-
var functionName = fullName;
|
144
|
-
var nameParts = fullName.split(".");
|
145
|
-
if(nameParts[0] == "[local]") {
|
146
|
-
functionName = nameParts[1];
|
147
|
-
} else if(nameParts.length > 1) {
|
148
|
-
functionName = nameParts.pop();
|
149
|
-
if(parentObject == window) {
|
150
|
-
var parentName = nameParts.join(".");
|
151
|
-
eval("parentObject = " + parentName);
|
152
|
-
}
|
153
|
-
}
|
154
|
-
functionGrabs[fullName] = new FunctionGrab(functionName, grabbed, parentObject);
|
155
|
-
return functionGrabs[fullName];
|
156
|
-
}
|
157
|
-
function grabObject(name, grabbed) {
|
158
|
-
objectGrabs[name] = new ObjectGrab(name, grabbed);
|
159
|
-
return objectGrabs[name];
|
160
|
-
}
|
161
|
-
function create(objectName, functionNames) {
|
162
|
-
var mockObject = {};
|
163
|
-
for(var i=0; i<functionNames.length; i++) {
|
164
|
-
mockObject[functionNames[i]] = function() {};
|
165
|
-
var fullName = objectName+"."+functionNames[i];
|
166
|
-
grabFunction(fullName, mockObject[functionNames[i]], mockObject);
|
167
|
-
}
|
168
|
-
return mockObject;
|
169
|
-
}
|
170
|
-
function inspect(name) {
|
171
|
-
return findGrab(name);
|
172
|
-
}
|
173
|
-
function expect(name) {
|
174
|
-
if(findGrab(name) == null) {
|
175
|
-
grab(name);
|
176
|
-
}
|
177
|
-
currentExpectation = findGrab(name).expect().once();
|
178
|
-
return currentExpectation;
|
179
|
-
}
|
180
|
-
function verify(name) {
|
181
|
-
if(findGrab(name) == null) {
|
182
|
-
grab(name);
|
183
|
-
}
|
184
|
-
currentExpectation = findGrab(name).expect().once();
|
185
|
-
return currentExpectation;
|
186
|
-
}
|
187
|
-
function report(name, expectation) {
|
188
|
-
return findGrab(name).report(expectation, name);
|
189
|
-
}
|
190
|
-
function reportAll(name) {
|
191
|
-
return findGrab(name).reportAll(name);
|
192
|
-
}
|
193
|
-
function findGrab(name) {
|
194
|
-
var parts = name.split(".");
|
195
|
-
if(parts.length == 1 && functionGrabs[name] != null) {
|
196
|
-
return functionGrabs[name];
|
197
|
-
} else if(parts.length == 1 && objectGrabs[name] != null) {
|
198
|
-
return objectGrabs[name];
|
199
|
-
} else {
|
200
|
-
if(functionGrabs[name] != null) {
|
201
|
-
return functionGrabs[name];
|
202
|
-
}
|
203
|
-
if(objectGrabs[name] != null) {
|
204
|
-
return objectGrabs[name];
|
205
|
-
}
|
206
|
-
if(objectGrabs[parts[0]] != null) {
|
207
|
-
return objectGrabs[parts[0]].examine(parts[1]);
|
208
|
-
}
|
209
|
-
return undefined;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
function resetGrabs() {
|
213
|
-
for(var g in functionGrabs) {
|
214
|
-
functionGrabs[g].reset();
|
215
|
-
}
|
216
|
-
for(var g in objectGrabs) {
|
217
|
-
objectGrabs[g].reset();
|
218
|
-
}
|
219
|
-
}
|
220
|
-
} // END Jack()
|
221
|
-
|
222
|
-
|
223
|
-
/**
|
224
|
-
* @functionName Name of grabbed function
|
225
|
-
* @grabbedFunction Reference to grabbed function
|
226
|
-
* @parentObject The object the function was grabbed from
|
227
|
-
*/
|
228
|
-
function FunctionGrab(functionName, grabbedFunction, parentObject) {
|
229
|
-
var invocations = [];
|
230
|
-
var specifications = [];
|
231
|
-
var emptyFunction = function(){};
|
232
|
-
|
233
|
-
init();
|
234
|
-
return {
|
235
|
-
'times': function() { return invocations.length; },
|
236
|
-
'reset': reset,
|
237
|
-
'expect': expect,
|
238
|
-
'specify': specify,
|
239
|
-
'report': report,
|
240
|
-
'reportAll': reportAll,
|
241
|
-
'mock': mock,
|
242
|
-
'stub': stub,
|
243
|
-
'arguments': getArguments,
|
244
|
-
'name': function() { return functionName }
|
245
|
-
};
|
246
|
-
|
247
|
-
function init() {
|
248
|
-
var original = parentObject[functionName];
|
249
|
-
var handler = function() {
|
250
|
-
return handleInvocation.apply(this,arguments);
|
251
|
-
}
|
252
|
-
for(var prop in original) {
|
253
|
-
handler[prop] = original[prop];
|
254
|
-
}
|
255
|
-
parentObject[functionName] = handler;
|
256
|
-
}
|
257
|
-
function handleInvocation() {
|
258
|
-
var invocation = new FunctionSpecification();
|
259
|
-
for(var i=0; i<arguments.length; i++) {
|
260
|
-
invocation.whereArgument(i).is(arguments[i]);
|
261
|
-
}
|
262
|
-
invocations.push(invocation);
|
263
|
-
var specification = findSpecificationFor(invocation);
|
264
|
-
if(specification == null) {
|
265
|
-
return grabbedFunction.apply(this, arguments);
|
266
|
-
} else if(specification.hasMockImplementation()) {
|
267
|
-
return specification.invoke.apply(this, arguments);
|
268
|
-
} else {
|
269
|
-
specification.invoke.apply(this, arguments);
|
270
|
-
return grabbedFunction.apply(this, arguments);
|
271
|
-
}
|
272
|
-
}
|
273
|
-
function matchInvocationsToSpecifications() {
|
274
|
-
for(var i=0; i<invocations.length; i++) {
|
275
|
-
var spec = findSpecificationFor(invocations[i]);
|
276
|
-
if(spec != null) {
|
277
|
-
|
278
|
-
}
|
279
|
-
}
|
280
|
-
}
|
281
|
-
function findSpecificationFor(invocation) {
|
282
|
-
for(var i=0; i<specifications.length; i++) {
|
283
|
-
var specification = specifications[i];
|
284
|
-
if(invocation.satisfies(specification)) {
|
285
|
-
return specification;
|
286
|
-
}
|
287
|
-
}
|
288
|
-
return null;
|
289
|
-
}
|
290
|
-
function isArgumentContstraintsMatching(invocation, expectation) {
|
291
|
-
var constr = expectation._argumentConstraints;
|
292
|
-
var arg = invocation.arguments;
|
293
|
-
if(constr == null) {
|
294
|
-
return true;
|
295
|
-
} else if(constr.length != arg.length) {
|
296
|
-
return false;
|
297
|
-
} else {
|
298
|
-
for(var i=0; i<constr.length; i++) {
|
299
|
-
if(!constr[i]) { continue; }
|
300
|
-
for(var j=0; j<constr[i].length; j++) {
|
301
|
-
if(typeof constr[i][j] == "function" && !constr[i][j](arg[i])) {
|
302
|
-
return false;
|
303
|
-
}
|
304
|
-
}
|
305
|
-
}
|
306
|
-
return true;
|
307
|
-
}
|
308
|
-
}
|
309
|
-
function reset() {
|
310
|
-
parentObject[functionName] = grabbedFunction;
|
311
|
-
}
|
312
|
-
function specify() {
|
313
|
-
var spec = new FunctionSpecification();
|
314
|
-
spec._id = specifications.length;
|
315
|
-
specifications.push(spec);
|
316
|
-
return spec;
|
317
|
-
}
|
318
|
-
function verify() {
|
319
|
-
|
320
|
-
}
|
321
|
-
function expect() {
|
322
|
-
return specify();
|
323
|
-
}
|
324
|
-
function mock(implementation) {
|
325
|
-
return expect().mock(implementation);
|
326
|
-
}
|
327
|
-
function stub() {
|
328
|
-
return expect();
|
329
|
-
}
|
330
|
-
function parseTimes(expression) {
|
331
|
-
var result = 0;
|
332
|
-
if("number" == typeof expression) {
|
333
|
-
result = expression;
|
334
|
-
} else if("string" == typeof expression) {
|
335
|
-
var parts = expression.split(" ");
|
336
|
-
result = parseInt(parts[0]);
|
337
|
-
}
|
338
|
-
return result;
|
339
|
-
}
|
340
|
-
function reportAll(fullName) {
|
341
|
-
var reports = [];
|
342
|
-
for(var i=0; i<specifications.length; i++) {
|
343
|
-
reports.push(report(specifications[i], fullName));
|
344
|
-
}
|
345
|
-
return reports;
|
346
|
-
}
|
347
|
-
function report(specification, fullName) {
|
348
|
-
if(specification == null) {
|
349
|
-
if(specifications.length == 0) {
|
350
|
-
var spec = specify().never();
|
351
|
-
for(var i=0; i<invocations.length; i++) {
|
352
|
-
spec.invoke();
|
353
|
-
}
|
354
|
-
}
|
355
|
-
specification = specifications[0];
|
356
|
-
}
|
357
|
-
var report = {};
|
358
|
-
report.expected = specification.invocations().expected;
|
359
|
-
report.actual = specification.invocations().actual;
|
360
|
-
report.success = specification.testTimes(report.actual);
|
361
|
-
report.fail = !report.success;
|
362
|
-
if(report.fail) {
|
363
|
-
report.message = "Expectation failed: " + specification.describe(fullName);
|
364
|
-
}
|
365
|
-
return report;
|
366
|
-
}
|
367
|
-
function generateReportMessage(report, fullName, argumentsDisplay) {
|
368
|
-
return report.messageParts.template
|
369
|
-
.replace("{name}",fullName)
|
370
|
-
.replace("{arguments}",argumentsDisplay)
|
371
|
-
.replace("{quantifier}",report.messageParts.quantifier)
|
372
|
-
.replace("{expected}",report.expected)
|
373
|
-
.replace("{actual}",report.actual);
|
374
|
-
}
|
375
|
-
function getArgumentsDisplay(expectation) {
|
376
|
-
if(expectation == null) {
|
377
|
-
return "";
|
378
|
-
}
|
379
|
-
var displayValues = [];
|
380
|
-
var constraints = expectation._argumentConstraints;
|
381
|
-
if(constraints == null) {
|
382
|
-
return "";
|
383
|
-
} else {
|
384
|
-
for(var i=0; i<constraints.length; i++) {
|
385
|
-
if(constraints[i] != null) {
|
386
|
-
displayValues.push(constraints[i][0].display);
|
387
|
-
} else {
|
388
|
-
displayValues.push('[any]');
|
389
|
-
}
|
390
|
-
}
|
391
|
-
return displayValues.join(', ');
|
392
|
-
}
|
393
|
-
}
|
394
|
-
function getArguments() {
|
395
|
-
return invocations[0].getArgumentValues();
|
396
|
-
}
|
397
|
-
} // END FunctionGrab()
|
398
|
-
|
399
|
-
|
400
|
-
/**
|
401
|
-
*
|
402
|
-
*/
|
403
|
-
function ObjectGrab(objectName, grabbedObject) {
|
404
|
-
var grabs = {};
|
405
|
-
|
406
|
-
init();
|
407
|
-
return {
|
408
|
-
'examine': getGrab,
|
409
|
-
'report': report,
|
410
|
-
'getGrab': getGrab,
|
411
|
-
'getGrabs': function() { return grabs },
|
412
|
-
'reset': reset
|
413
|
-
};
|
414
|
-
|
415
|
-
function init() {
|
416
|
-
for(key in grabbedObject) {
|
417
|
-
var property = grabbedObject[key];
|
418
|
-
if("function" == typeof property) {
|
419
|
-
grabs[key] = new FunctionGrab(key, property, grabbedObject);
|
420
|
-
}
|
421
|
-
}
|
422
|
-
}
|
423
|
-
function report(name) {
|
424
|
-
var allReports = [];
|
425
|
-
for(var g in grabs) {
|
426
|
-
var reports = grabs[g].reportAll(name+"."+grabs[g].name());
|
427
|
-
for(var i=0; i<reports.length; i++) {
|
428
|
-
allReports.push(reports[i]);
|
429
|
-
}
|
430
|
-
}
|
431
|
-
return allReports;
|
432
|
-
}
|
433
|
-
function getGrab(name) {
|
434
|
-
return grabs[name];
|
435
|
-
}
|
436
|
-
function reset() {
|
437
|
-
for(var g in grabs) {
|
438
|
-
grabs[g].reset();
|
439
|
-
}
|
440
|
-
}
|
441
|
-
}
|
442
|
-
|
443
|
-
|
444
|
-
/**
|
445
|
-
*
|
446
|
-
*/
|
447
|
-
function Environment() {
|
448
|
-
var reportingEnabled = true;
|
449
|
-
init();
|
450
|
-
return {
|
451
|
-
'isJSSpec': isJSSpec,
|
452
|
-
'isScriptaculous': isScriptaculous,
|
453
|
-
'report': report,
|
454
|
-
'disableReporting': function() { reportingEnabled = false; },
|
455
|
-
'enableReporting': function() { reportingEnabled = true; },
|
456
|
-
'reset': function() {}
|
457
|
-
}
|
458
|
-
function init() {
|
459
|
-
|
460
|
-
}
|
461
|
-
function isJSSpec() {
|
462
|
-
return window.JSSpec != null;
|
463
|
-
}
|
464
|
-
function isScriptaculous() {
|
465
|
-
return window.Test != null && window.Test.Unit != null && window.Test.Unit.Runner != null;
|
466
|
-
}
|
467
|
-
function report(message) {
|
468
|
-
if(!reportingEnabled) { return; }
|
469
|
-
if(isScriptaculous()) {
|
470
|
-
throw new Error(message);
|
471
|
-
} else if(isJSSpec()) {
|
472
|
-
throw new Error(message);
|
473
|
-
}
|
474
|
-
}
|
475
|
-
}
|
476
|
-
|
477
|
-
/**
|
478
|
-
*
|
479
|
-
*/
|
480
|
-
function Util() {
|
481
|
-
return {
|
482
|
-
'displayValue': displayValue
|
483
|
-
}
|
484
|
-
|
485
|
-
function displayValue() {
|
486
|
-
var value = arguments[0];
|
487
|
-
var prefix = "";
|
488
|
-
if(arguments.length > 1) {
|
489
|
-
value = arguments[1];
|
490
|
-
prefix = arguments[0];
|
491
|
-
}
|
492
|
-
if(value == undefined) {
|
493
|
-
return displayValueNullOrUndefined(value);
|
494
|
-
}
|
495
|
-
var display = displayValueDefault(value);
|
496
|
-
if('string' == typeof value) {
|
497
|
-
display = displayValueString(value);
|
498
|
-
} else if(value.constructor == Array) {
|
499
|
-
display = displayValueArray(value);
|
500
|
-
} else if(value.constructor == RegExp) {
|
501
|
-
display = displayValueRegExp(value);
|
502
|
-
} else if('object' == typeof value) {
|
503
|
-
display = displayValueObject(value);
|
504
|
-
}
|
505
|
-
return prefix + display;
|
506
|
-
}
|
507
|
-
function displayValueDefault(value) {
|
508
|
-
return value.toString();
|
509
|
-
}
|
510
|
-
function displayValueString(value) {
|
511
|
-
return "'" + value + "'";
|
512
|
-
}
|
513
|
-
function displayValueArray(value) {
|
514
|
-
var displayValues = [];
|
515
|
-
for(var i=0; i<value.length; i++) {
|
516
|
-
displayValues.push(displayValue(value[i]));
|
517
|
-
}
|
518
|
-
return "[" + displayValues.join(",") + "]";
|
519
|
-
}
|
520
|
-
function displayValueNullOrUndefined(value) {
|
521
|
-
if(value === undefined) {
|
522
|
-
return "undefined";
|
523
|
-
} else if(value === null) {
|
524
|
-
return "null";
|
525
|
-
}
|
526
|
-
}
|
527
|
-
function displayValueRegExp(value) {
|
528
|
-
return value.toString();
|
529
|
-
}
|
530
|
-
function displayValueObject(value) {
|
531
|
-
var keyValues = [];
|
532
|
-
for(var p in value) {
|
533
|
-
keyValues.push(p + ':' + displayValue(value[p]));
|
534
|
-
}
|
535
|
-
return '{' + keyValues.join(',') + '}';
|
536
|
-
}
|
537
|
-
}
|
538
|
-
|
539
|
-
/**
|
540
|
-
*
|
541
|
-
*/
|
542
|
-
function FunctionSpecification() {
|
543
|
-
var constraints = null;
|
544
|
-
var argumentValues = [];
|
545
|
-
var mockImplementation = null;
|
546
|
-
var timing = {actual: 0, expected: 1, modifier: 0};
|
547
|
-
|
548
|
-
var api = createApi();
|
549
|
-
return api;
|
550
|
-
|
551
|
-
function createApi() {
|
552
|
-
var api = {};
|
553
|
-
mixinMatchers(api);
|
554
|
-
mixinTiming(api);
|
555
|
-
api.test = test;
|
556
|
-
api.testTimes = testTimes;
|
557
|
-
api.satisfies = satisfies;
|
558
|
-
api.invoke = invoke;
|
559
|
-
api.mock = mock;
|
560
|
-
api.stub = stub;
|
561
|
-
api.returnValue = returnValue;
|
562
|
-
api.describe = describe;
|
563
|
-
api.invocations = invocations;
|
564
|
-
api.getArgumentValues = getArgumentValues;
|
565
|
-
api.hasMockImplementation = hasMockImplementation;
|
566
|
-
return api;
|
567
|
-
}
|
568
|
-
function mixinMatchers(api) {
|
569
|
-
api.whereArgument = function(argIndex) {
|
570
|
-
var collected = {};
|
571
|
-
for(var name in jack.matchers) {
|
572
|
-
addMatcher(argIndex, name, collected)
|
573
|
-
}
|
574
|
-
return collected;
|
575
|
-
}
|
576
|
-
api.withArguments = function() {
|
577
|
-
for(var i=0; i<arguments.length; i++) {
|
578
|
-
api.whereArgument(i).is(arguments[i]);
|
579
|
-
}
|
580
|
-
return api;
|
581
|
-
}
|
582
|
-
api.withNoArguments = function() { constraints = []; return api; }
|
583
|
-
return api;
|
584
|
-
|
585
|
-
function addMatcher(argIndex, name, collection) {
|
586
|
-
collection[name] = function() {
|
587
|
-
addConstraint(argIndex, jack.matchers[name], arguments);
|
588
|
-
if(name == "is") {
|
589
|
-
addArgumentValue(argIndex, arguments[0]);
|
590
|
-
}
|
591
|
-
return api;
|
592
|
-
}
|
593
|
-
}
|
594
|
-
}
|
595
|
-
function mixinTiming(api) {
|
596
|
-
api.exactly = function(times) {
|
597
|
-
timing.expected = parseTimes(times);
|
598
|
-
return api;
|
599
|
-
}
|
600
|
-
api.once = function() {
|
601
|
-
timing.expected = 1;
|
602
|
-
return api;
|
603
|
-
}
|
604
|
-
api.atLeast = function(times) {
|
605
|
-
timing.expected = parseTimes(times);
|
606
|
-
timing.modifier = 1;
|
607
|
-
return api;
|
608
|
-
}
|
609
|
-
api.atMost = function(times) {
|
610
|
-
timing.expected = parseTimes(times);
|
611
|
-
timing.modifier = -1;
|
612
|
-
return api;
|
613
|
-
}
|
614
|
-
api.never = function() {
|
615
|
-
timing.expected = 0;
|
616
|
-
return api;
|
617
|
-
}
|
618
|
-
|
619
|
-
function parseTimes(times) {
|
620
|
-
return parseInt(times);
|
621
|
-
}
|
622
|
-
}
|
623
|
-
function addArgumentValue(index, value) {
|
624
|
-
argumentValues[index] = value;
|
625
|
-
}
|
626
|
-
function addConstraint(argIndex, matcher, matcherArguments) {
|
627
|
-
createConstraintsArrayIfNull(argIndex);
|
628
|
-
var constraint = function(value) {
|
629
|
-
var allArguments = [value];
|
630
|
-
for(var i=0; i<matcherArguments.length; i++) {
|
631
|
-
allArguments.push(matcherArguments[i]);
|
632
|
-
}
|
633
|
-
var test = matcher.apply(null, allArguments);
|
634
|
-
return test.result;
|
635
|
-
}
|
636
|
-
constraints[argIndex].push(constraint);
|
637
|
-
constraints[argIndex].describe = function() {
|
638
|
-
var allArguments = [""];
|
639
|
-
for(var i=0; i<matcherArguments.length; i++) {
|
640
|
-
allArguments.push(matcherArguments[i]);
|
641
|
-
}
|
642
|
-
return matcher.apply(null, allArguments).expected;
|
643
|
-
}
|
644
|
-
}
|
645
|
-
function createConstraintsArrayIfNull(argIndex) {
|
646
|
-
if(constraints == null) {
|
647
|
-
constraints = [];
|
648
|
-
}
|
649
|
-
if(constraints[argIndex] == null) {
|
650
|
-
constraints[argIndex] = [];
|
651
|
-
}
|
652
|
-
}
|
653
|
-
function test() {
|
654
|
-
var result = true;
|
655
|
-
if(constraints != null) {
|
656
|
-
if(constraints.length != arguments.length) {
|
657
|
-
result = false;
|
658
|
-
} else {
|
659
|
-
for (var i = 0; i < constraints.length; i++) {
|
660
|
-
var oneArgumentsConstraints = constraints[i];
|
661
|
-
if (oneArgumentsConstraints != null) {
|
662
|
-
for (var j = 0; j < oneArgumentsConstraints.length; j++) {
|
663
|
-
var constraint = oneArgumentsConstraints[j];
|
664
|
-
if (constraint && !constraint(arguments[i])) {
|
665
|
-
result = false;
|
666
|
-
}
|
667
|
-
}
|
668
|
-
}
|
669
|
-
}
|
670
|
-
}
|
671
|
-
}
|
672
|
-
return result;
|
673
|
-
}
|
674
|
-
function testTimes(times) {
|
675
|
-
if(timing.modifier == 0) {
|
676
|
-
return times == timing.expected;
|
677
|
-
} else if(timing.modifier == 1) {
|
678
|
-
return times >= timing.expected;
|
679
|
-
} else if(timing.modifier == -1) {
|
680
|
-
return times <= timing.expected;
|
681
|
-
}
|
682
|
-
}
|
683
|
-
function satisfies(other) {
|
684
|
-
return other.test.apply(this, argumentValues);
|
685
|
-
}
|
686
|
-
function invoke() {
|
687
|
-
timing.actual++;
|
688
|
-
if(mockImplementation != null) {
|
689
|
-
return mockImplementation.apply(this, arguments);
|
690
|
-
}
|
691
|
-
}
|
692
|
-
function mock(implementation) {
|
693
|
-
mockImplementation = implementation;
|
694
|
-
return api;
|
695
|
-
}
|
696
|
-
function stub() {
|
697
|
-
mockImplementation = function() {};
|
698
|
-
return api;
|
699
|
-
}
|
700
|
-
function returnValue(value) {
|
701
|
-
mockImplementation = function() {
|
702
|
-
return value;
|
703
|
-
}
|
704
|
-
}
|
705
|
-
function hasMockImplementation() {
|
706
|
-
return mockImplementation != null;
|
707
|
-
}
|
708
|
-
function invocations() {
|
709
|
-
return {
|
710
|
-
actual: timing.actual,
|
711
|
-
expected: timing.expected
|
712
|
-
};
|
713
|
-
}
|
714
|
-
function getArgumentValues() {
|
715
|
-
return argumentValues;
|
716
|
-
}
|
717
|
-
function describe(name) {
|
718
|
-
return name +"(" + describeConstraints() + ") " + describeTimes();
|
719
|
-
}
|
720
|
-
function describeConstraints() {
|
721
|
-
if(constraints == null) {
|
722
|
-
return "";
|
723
|
-
}
|
724
|
-
var descriptions = [];
|
725
|
-
for(var i=0; i<constraints.length; i++) {
|
726
|
-
if(constraints[i] != null) {
|
727
|
-
descriptions.push(constraints[i].describe());
|
728
|
-
} else {
|
729
|
-
descriptions.push("[any]");
|
730
|
-
}
|
731
|
-
}
|
732
|
-
return descriptions.join(", ");
|
733
|
-
}
|
734
|
-
function describeTimes() {
|
735
|
-
var description = timing.expected;
|
736
|
-
if(timing.expected == 1) {
|
737
|
-
description += " time";
|
738
|
-
} else {
|
739
|
-
description += " times";
|
740
|
-
}
|
741
|
-
if(timing.modifier == 0) {
|
742
|
-
description = "expected exactly " + description;
|
743
|
-
} else if(timing.modifier > 0) {
|
744
|
-
description = "expected at least " + description;
|
745
|
-
} else if(timing.modifier < 0) {
|
746
|
-
description = "expected at most " + description;
|
747
|
-
}
|
748
|
-
description += ", called " + timing.actual + " time";
|
749
|
-
if(timing.actual != 1) {
|
750
|
-
description += "s";
|
751
|
-
}
|
752
|
-
return description;
|
753
|
-
}
|
754
|
-
}
|
755
|
-
|
756
|
-
|
757
|
-
/**
|
758
|
-
*
|
759
|
-
*/
|
760
|
-
function Matchers() {
|
761
|
-
return {
|
762
|
-
'is':
|
763
|
-
function(a, b) {
|
764
|
-
return result(a==b, a, '', b);
|
765
|
-
},
|
766
|
-
'isNot':
|
767
|
-
function(a, b) {
|
768
|
-
return result(a!=b, a, 'not:', b);
|
769
|
-
},
|
770
|
-
'isType':
|
771
|
-
function(a, b) {
|
772
|
-
return result(b == typeof a, a, 'type:', b);
|
773
|
-
},
|
774
|
-
'matches':
|
775
|
-
function(a, b) {
|
776
|
-
return result(b.test(a), a, 'matching:', b)
|
777
|
-
},
|
778
|
-
'hasProperty':
|
779
|
-
function(a, b, c) {
|
780
|
-
var match = c ? a[b]==c : a[b]!=undefined;
|
781
|
-
var bDisplay = b;
|
782
|
-
if(c != null) {
|
783
|
-
bDisplay = {};
|
784
|
-
bDisplay[b] = c;
|
785
|
-
}
|
786
|
-
return result(match, a, 'property:', bDisplay)
|
787
|
-
},
|
788
|
-
'hasProperties':
|
789
|
-
function(a, b) {
|
790
|
-
var match = true;
|
791
|
-
for(var p in b) {
|
792
|
-
if(a[p] != b[p]) {
|
793
|
-
match = false;
|
794
|
-
}
|
795
|
-
}
|
796
|
-
return result(match, a, 'properties:', b);
|
797
|
-
},
|
798
|
-
'isGreaterThan':
|
799
|
-
function(a, b) {
|
800
|
-
return result(b < a, a, '>', b);
|
801
|
-
},
|
802
|
-
'isLessThan':
|
803
|
-
function(a, b) {
|
804
|
-
return result(b > a, a, '<', b);
|
805
|
-
},
|
806
|
-
'isOneOf':
|
807
|
-
function() {
|
808
|
-
var a = arguments[0];
|
809
|
-
var b = [];
|
810
|
-
for(var i=1; i<arguments.length; i++) {
|
811
|
-
b.push(arguments[i]);
|
812
|
-
}
|
813
|
-
var match = false;
|
814
|
-
for(var i=0; i<b.length; i++) {
|
815
|
-
if(b[i] == a) {
|
816
|
-
match = true;
|
817
|
-
}
|
818
|
-
}
|
819
|
-
return result(match, a, 'oneOf:', b);
|
820
|
-
}
|
821
|
-
}
|
822
|
-
|
823
|
-
function result(match, actual, prefix, expected) {
|
824
|
-
return {
|
825
|
-
result: match,
|
826
|
-
actual: jack.util.displayValue(actual),
|
827
|
-
expected: jack.util.displayValue(prefix, expected)
|
828
|
-
}
|
829
|
-
}
|
830
|
-
}
|
831
|
-
|
832
|
-
})(); // END HIDING FROM GLOBAL SCOPE
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|