scratch – Blame information for rev 133
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
75 | office | 1 | /* |
2 | Copyright (c) 2008-2013 Pivotal Labs |
||
3 | |||
4 | Permission is hereby granted, free of charge, to any person obtaining |
||
5 | a copy of this software and associated documentation files (the |
||
6 | "Software"), to deal in the Software without restriction, including |
||
7 | without limitation the rights to use, copy, modify, merge, publish, |
||
8 | distribute, sublicense, and/or sell copies of the Software, and to |
||
9 | permit persons to whom the Software is furnished to do so, subject to |
||
10 | the following conditions: |
||
11 | |||
12 | The above copyright notice and this permission notice shall be |
||
13 | included in all copies or substantial portions of the Software. |
||
14 | |||
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
22 | */ |
||
23 | function getJasmineRequireObj() { |
||
24 | if (typeof module !== "undefined" && module.exports) { |
||
25 | return exports; |
||
26 | } else { |
||
27 | window.jasmineRequire = window.jasmineRequire || {}; |
||
28 | return window.jasmineRequire; |
||
29 | } |
||
30 | } |
||
31 | |||
32 | getJasmineRequireObj().core = function(jRequire) { |
||
33 | var j$ = {}; |
||
34 | |||
35 | jRequire.base(j$); |
||
36 | j$.util = jRequire.util(); |
||
37 | j$.Any = jRequire.Any(); |
||
38 | j$.CallTracker = jRequire.CallTracker(); |
||
39 | j$.Clock = jRequire.Clock(); |
||
40 | j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(); |
||
41 | j$.Env = jRequire.Env(j$); |
||
42 | j$.ExceptionFormatter = jRequire.ExceptionFormatter(); |
||
43 | j$.Expectation = jRequire.Expectation(); |
||
44 | j$.buildExpectationResult = jRequire.buildExpectationResult(); |
||
45 | j$.JsApiReporter = jRequire.JsApiReporter(); |
||
46 | j$.matchersUtil = jRequire.matchersUtil(j$); |
||
47 | j$.ObjectContaining = jRequire.ObjectContaining(j$); |
||
48 | j$.pp = jRequire.pp(j$); |
||
49 | j$.QueueRunner = jRequire.QueueRunner(); |
||
50 | j$.ReportDispatcher = jRequire.ReportDispatcher(); |
||
51 | j$.Spec = jRequire.Spec(j$); |
||
52 | j$.SpyStrategy = jRequire.SpyStrategy(); |
||
53 | j$.Suite = jRequire.Suite(); |
||
54 | j$.Timer = jRequire.Timer(); |
||
55 | j$.version = jRequire.version(); |
||
56 | |||
57 | j$.matchers = jRequire.requireMatchers(jRequire, j$); |
||
58 | |||
59 | return j$; |
||
60 | }; |
||
61 | |||
62 | getJasmineRequireObj().requireMatchers = function(jRequire, j$) { |
||
63 | var availableMatchers = [ |
||
64 | "toBe", |
||
65 | "toBeCloseTo", |
||
66 | "toBeDefined", |
||
67 | "toBeFalsy", |
||
68 | "toBeGreaterThan", |
||
69 | "toBeLessThan", |
||
70 | "toBeNaN", |
||
71 | "toBeNull", |
||
72 | "toBeTruthy", |
||
73 | "toBeUndefined", |
||
74 | "toContain", |
||
75 | "toEqual", |
||
76 | "toHaveBeenCalled", |
||
77 | "toHaveBeenCalledWith", |
||
78 | "toMatch", |
||
79 | "toThrow", |
||
80 | "toThrowError" |
||
81 | ], |
||
82 | matchers = {}; |
||
83 | |||
84 | for (var i = 0; i < availableMatchers.length; i++) { |
||
85 | var name = availableMatchers[i]; |
||
86 | matchers[name] = jRequire[name](j$); |
||
87 | } |
||
88 | |||
89 | return matchers; |
||
90 | }; |
||
91 | |||
92 | getJasmineRequireObj().base = function(j$) { |
||
93 | j$.unimplementedMethod_ = function() { |
||
94 | throw new Error("unimplemented method"); |
||
95 | }; |
||
96 | |||
97 | j$.MAX_PRETTY_PRINT_DEPTH = 40; |
||
98 | j$.DEFAULT_TIMEOUT_INTERVAL = 5000; |
||
99 | |||
100 | j$.getGlobal = (function() { |
||
101 | var jasmineGlobal = eval.call(null, "this"); |
||
102 | return function() { |
||
103 | return jasmineGlobal; |
||
104 | }; |
||
105 | })(); |
||
106 | |||
107 | j$.getEnv = function(options) { |
||
108 | var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options); |
||
109 | //jasmine. singletons in here (setTimeout blah blah). |
||
110 | return env; |
||
111 | }; |
||
112 | |||
113 | j$.isArray_ = function(value) { |
||
114 | return j$.isA_("Array", value); |
||
115 | }; |
||
116 | |||
117 | j$.isString_ = function(value) { |
||
118 | return j$.isA_("String", value); |
||
119 | }; |
||
120 | |||
121 | j$.isNumber_ = function(value) { |
||
122 | return j$.isA_("Number", value); |
||
123 | }; |
||
124 | |||
125 | j$.isA_ = function(typeName, value) { |
||
126 | return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; |
||
127 | }; |
||
128 | |||
129 | j$.isDomNode = function(obj) { |
||
130 | return obj.nodeType > 0; |
||
131 | }; |
||
132 | |||
133 | j$.any = function(clazz) { |
||
134 | return new j$.Any(clazz); |
||
135 | }; |
||
136 | |||
137 | j$.objectContaining = function(sample) { |
||
138 | return new j$.ObjectContaining(sample); |
||
139 | }; |
||
140 | |||
141 | j$.createSpy = function(name, originalFn) { |
||
142 | |||
143 | var spyStrategy = new j$.SpyStrategy({ |
||
144 | name: name, |
||
145 | fn: originalFn, |
||
146 | getSpy: function() { return spy; } |
||
147 | }), |
||
148 | callTracker = new j$.CallTracker(), |
||
149 | spy = function() { |
||
150 | callTracker.track({ |
||
151 | object: this, |
||
152 | args: Array.prototype.slice.apply(arguments) |
||
153 | }); |
||
154 | return spyStrategy.exec.apply(this, arguments); |
||
155 | }; |
||
156 | |||
157 | for (var prop in originalFn) { |
||
158 | if (prop === 'and' || prop === 'calls') { |
||
159 | throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon"); |
||
160 | } |
||
161 | |||
162 | spy[prop] = originalFn[prop]; |
||
163 | } |
||
164 | |||
165 | spy.and = spyStrategy; |
||
166 | spy.calls = callTracker; |
||
167 | |||
168 | return spy; |
||
169 | }; |
||
170 | |||
171 | j$.isSpy = function(putativeSpy) { |
||
172 | if (!putativeSpy) { |
||
173 | return false; |
||
174 | } |
||
175 | return putativeSpy.and instanceof j$.SpyStrategy && |
||
176 | putativeSpy.calls instanceof j$.CallTracker; |
||
177 | }; |
||
178 | |||
179 | j$.createSpyObj = function(baseName, methodNames) { |
||
180 | if (!j$.isArray_(methodNames) || methodNames.length === 0) { |
||
181 | throw "createSpyObj requires a non-empty array of method names to create spies for"; |
||
182 | } |
||
183 | var obj = {}; |
||
184 | for (var i = 0; i < methodNames.length; i++) { |
||
185 | obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]); |
||
186 | } |
||
187 | return obj; |
||
188 | }; |
||
189 | }; |
||
190 | |||
191 | getJasmineRequireObj().util = function() { |
||
192 | |||
193 | var util = {}; |
||
194 | |||
195 | util.inherit = function(childClass, parentClass) { |
||
196 | var Subclass = function() { |
||
197 | }; |
||
198 | Subclass.prototype = parentClass.prototype; |
||
199 | childClass.prototype = new Subclass(); |
||
200 | }; |
||
201 | |||
202 | util.htmlEscape = function(str) { |
||
203 | if (!str) { |
||
204 | return str; |
||
205 | } |
||
206 | return str.replace(/&/g, '&') |
||
207 | .replace(/g, '<') |
||
208 | .replace(/>/g, '>'); |
||
209 | }; |
||
210 | |||
211 | util.argsToArray = function(args) { |
||
212 | var arrayOfArgs = []; |
||
213 | for (var i = 0; i < args.length; i++) { |
||
214 | arrayOfArgs.push(args[i]); |
||
215 | } |
||
216 | return arrayOfArgs; |
||
217 | }; |
||
218 | |||
219 | util.isUndefined = function(obj) { |
||
220 | return obj === void 0; |
||
221 | }; |
||
222 | |||
223 | return util; |
||
224 | }; |
||
225 | |||
226 | getJasmineRequireObj().Spec = function(j$) { |
||
227 | function Spec(attrs) { |
||
228 | this.expectationFactory = attrs.expectationFactory; |
||
229 | this.resultCallback = attrs.resultCallback || function() {}; |
||
230 | this.id = attrs.id; |
||
231 | this.description = attrs.description || ''; |
||
232 | this.fn = attrs.fn; |
||
233 | this.beforeFns = attrs.beforeFns || function() { return []; }; |
||
234 | this.afterFns = attrs.afterFns || function() { return []; }; |
||
235 | this.onStart = attrs.onStart || function() {}; |
||
236 | this.exceptionFormatter = attrs.exceptionFormatter || function() {}; |
||
237 | this.getSpecName = attrs.getSpecName || function() { return ''; }; |
||
238 | this.expectationResultFactory = attrs.expectationResultFactory || function() { }; |
||
239 | this.queueRunnerFactory = attrs.queueRunnerFactory || function() {}; |
||
240 | this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; |
||
241 | |||
242 | this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout}; |
||
243 | |||
244 | if (!this.fn) { |
||
245 | this.pend(); |
||
246 | } |
||
247 | |||
248 | this.result = { |
||
249 | id: this.id, |
||
250 | description: this.description, |
||
251 | fullName: this.getFullName(), |
||
252 | failedExpectations: [] |
||
253 | }; |
||
254 | } |
||
255 | |||
256 | Spec.prototype.addExpectationResult = function(passed, data) { |
||
257 | if (passed) { |
||
258 | return; |
||
259 | } |
||
260 | this.result.failedExpectations.push(this.expectationResultFactory(data)); |
||
261 | }; |
||
262 | |||
263 | Spec.prototype.expect = function(actual) { |
||
264 | return this.expectationFactory(actual, this); |
||
265 | }; |
||
266 | |||
267 | Spec.prototype.execute = function(onComplete) { |
||
268 | var self = this, |
||
269 | timeout; |
||
270 | |||
271 | this.onStart(this); |
||
272 | |||
273 | if (this.markedPending || this.disabled) { |
||
274 | complete(); |
||
275 | return; |
||
276 | } |
||
277 | |||
278 | function timeoutable(fn) { |
||
279 | return function(done) { |
||
280 | timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() { |
||
281 | onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.')); |
||
282 | done(); |
||
283 | }, j$.DEFAULT_TIMEOUT_INTERVAL]]); |
||
284 | |||
285 | var callDone = function() { |
||
286 | clearTimeoutable(); |
||
287 | done(); |
||
288 | }; |
||
289 | |||
290 | fn.call(this, callDone); //TODO: do we care about more than 1 arg? |
||
291 | }; |
||
292 | } |
||
293 | |||
294 | function clearTimeoutable() { |
||
295 | Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]); |
||
296 | timeout = void 0; |
||
297 | } |
||
298 | |||
299 | var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()), |
||
300 | allTimeoutableFns = []; |
||
301 | for (var i = 0; i < allFns.length; i++) { |
||
302 | var fn = allFns[i]; |
||
303 | allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn); |
||
304 | } |
||
305 | |||
306 | this.queueRunnerFactory({ |
||
307 | fns: allTimeoutableFns, |
||
308 | onException: onException, |
||
309 | onComplete: complete |
||
310 | }); |
||
311 | |||
312 | function onException(e) { |
||
313 | clearTimeoutable(); |
||
314 | if (Spec.isPendingSpecException(e)) { |
||
315 | self.pend(); |
||
316 | return; |
||
317 | } |
||
318 | |||
319 | self.addExpectationResult(false, { |
||
320 | matcherName: "", |
||
321 | passed: false, |
||
322 | expected: "", |
||
323 | actual: "", |
||
324 | error: e |
||
325 | }); |
||
326 | } |
||
327 | |||
328 | function complete() { |
||
329 | self.result.status = self.status(); |
||
330 | self.resultCallback(self.result); |
||
331 | |||
332 | if (onComplete) { |
||
333 | onComplete(); |
||
334 | } |
||
335 | } |
||
336 | }; |
||
337 | |||
338 | Spec.prototype.disable = function() { |
||
339 | this.disabled = true; |
||
340 | }; |
||
341 | |||
342 | Spec.prototype.pend = function() { |
||
343 | this.markedPending = true; |
||
344 | }; |
||
345 | |||
346 | Spec.prototype.status = function() { |
||
347 | if (this.disabled) { |
||
348 | return 'disabled'; |
||
349 | } |
||
350 | |||
351 | if (this.markedPending) { |
||
352 | return 'pending'; |
||
353 | } |
||
354 | |||
355 | if (this.result.failedExpectations.length > 0) { |
||
356 | return 'failed'; |
||
357 | } else { |
||
358 | return 'passed'; |
||
359 | } |
||
360 | }; |
||
361 | |||
362 | Spec.prototype.getFullName = function() { |
||
363 | return this.getSpecName(this); |
||
364 | }; |
||
365 | |||
366 | Spec.pendingSpecExceptionMessage = "=> marked Pending"; |
||
367 | |||
368 | Spec.isPendingSpecException = function(e) { |
||
369 | return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1; |
||
370 | }; |
||
371 | |||
372 | return Spec; |
||
373 | }; |
||
374 | |||
375 | if (typeof window == void 0 && typeof exports == "object") { |
||
376 | exports.Spec = jasmineRequire.Spec; |
||
377 | } |
||
378 | |||
379 | getJasmineRequireObj().Env = function(j$) { |
||
380 | function Env(options) { |
||
381 | options = options || {}; |
||
382 | |||
383 | var self = this; |
||
384 | var global = options.global || j$.getGlobal(); |
||
385 | |||
386 | var totalSpecsDefined = 0; |
||
387 | |||
388 | var catchExceptions = true; |
||
389 | |||
390 | var realSetTimeout = j$.getGlobal().setTimeout; |
||
391 | var realClearTimeout = j$.getGlobal().clearTimeout; |
||
392 | this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler()); |
||
393 | |||
394 | var runnableLookupTable = {}; |
||
395 | |||
396 | var spies = []; |
||
397 | |||
398 | var currentSpec = null; |
||
399 | var currentSuite = null; |
||
400 | |||
401 | var reporter = new j$.ReportDispatcher([ |
||
402 | "jasmineStarted", |
||
403 | "jasmineDone", |
||
404 | "suiteStarted", |
||
405 | "suiteDone", |
||
406 | "specStarted", |
||
407 | "specDone" |
||
408 | ]); |
||
409 | |||
410 | this.specFilter = function() { |
||
411 | return true; |
||
412 | }; |
||
413 | |||
414 | var equalityTesters = []; |
||
415 | |||
416 | var customEqualityTesters = []; |
||
417 | this.addCustomEqualityTester = function(tester) { |
||
418 | customEqualityTesters.push(tester); |
||
419 | }; |
||
420 | |||
421 | j$.Expectation.addCoreMatchers(j$.matchers); |
||
422 | |||
423 | var nextSpecId = 0; |
||
424 | var getNextSpecId = function() { |
||
425 | return 'spec' + nextSpecId++; |
||
426 | }; |
||
427 | |||
428 | var nextSuiteId = 0; |
||
429 | var getNextSuiteId = function() { |
||
430 | return 'suite' + nextSuiteId++; |
||
431 | }; |
||
432 | |||
433 | var expectationFactory = function(actual, spec) { |
||
434 | return j$.Expectation.Factory({ |
||
435 | util: j$.matchersUtil, |
||
436 | customEqualityTesters: customEqualityTesters, |
||
437 | actual: actual, |
||
438 | addExpectationResult: addExpectationResult |
||
439 | }); |
||
440 | |||
441 | function addExpectationResult(passed, result) { |
||
442 | return spec.addExpectationResult(passed, result); |
||
443 | } |
||
444 | }; |
||
445 | |||
446 | var specStarted = function(spec) { |
||
447 | currentSpec = spec; |
||
448 | reporter.specStarted(spec.result); |
||
449 | }; |
||
450 | |||
451 | var beforeFns = function(suite) { |
||
452 | return function() { |
||
453 | var befores = []; |
||
454 | while(suite) { |
||
455 | befores = befores.concat(suite.beforeFns); |
||
456 | suite = suite.parentSuite; |
||
457 | } |
||
458 | return befores.reverse(); |
||
459 | }; |
||
460 | }; |
||
461 | |||
462 | var afterFns = function(suite) { |
||
463 | return function() { |
||
464 | var afters = []; |
||
465 | while(suite) { |
||
466 | afters = afters.concat(suite.afterFns); |
||
467 | suite = suite.parentSuite; |
||
468 | } |
||
469 | return afters; |
||
470 | }; |
||
471 | }; |
||
472 | |||
473 | var getSpecName = function(spec, suite) { |
||
474 | return suite.getFullName() + ' ' + spec.description; |
||
475 | }; |
||
476 | |||
477 | // TODO: we may just be able to pass in the fn instead of wrapping here |
||
478 | var buildExpectationResult = j$.buildExpectationResult, |
||
479 | exceptionFormatter = new j$.ExceptionFormatter(), |
||
480 | expectationResultFactory = function(attrs) { |
||
481 | attrs.messageFormatter = exceptionFormatter.message; |
||
482 | attrs.stackFormatter = exceptionFormatter.stack; |
||
483 | |||
484 | return buildExpectationResult(attrs); |
||
485 | }; |
||
486 | |||
487 | // TODO: fix this naming, and here's where the value comes in |
||
488 | this.catchExceptions = function(value) { |
||
489 | catchExceptions = !!value; |
||
490 | return catchExceptions; |
||
491 | }; |
||
492 | |||
493 | this.catchingExceptions = function() { |
||
494 | return catchExceptions; |
||
495 | }; |
||
496 | |||
497 | var maximumSpecCallbackDepth = 20; |
||
498 | var currentSpecCallbackDepth = 0; |
||
499 | |||
500 | function clearStack(fn) { |
||
501 | currentSpecCallbackDepth++; |
||
502 | if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) { |
||
503 | currentSpecCallbackDepth = 0; |
||
504 | realSetTimeout(fn, 0); |
||
505 | } else { |
||
506 | fn(); |
||
507 | } |
||
508 | } |
||
509 | |||
510 | var catchException = function(e) { |
||
511 | return j$.Spec.isPendingSpecException(e) || catchExceptions; |
||
512 | }; |
||
513 | |||
514 | var queueRunnerFactory = function(options) { |
||
515 | options.catchException = catchException; |
||
516 | options.clearStack = options.clearStack || clearStack; |
||
517 | |||
518 | new j$.QueueRunner(options).execute(); |
||
519 | }; |
||
520 | |||
521 | var topSuite = new j$.Suite({ |
||
522 | env: this, |
||
523 | id: getNextSuiteId(), |
||
524 | description: 'Jasmine__TopLevel__Suite', |
||
525 | queueRunner: queueRunnerFactory, |
||
526 | resultCallback: function() {} // TODO - hook this up |
||
527 | }); |
||
528 | runnableLookupTable[topSuite.id] = topSuite; |
||
529 | currentSuite = topSuite; |
||
530 | |||
531 | this.topSuite = function() { |
||
532 | return topSuite; |
||
533 | }; |
||
534 | |||
535 | this.execute = function(runnablesToRun) { |
||
536 | runnablesToRun = runnablesToRun || [topSuite.id]; |
||
537 | |||
538 | var allFns = []; |
||
539 | for(var i = 0; i < runnablesToRun.length; i++) { |
||
540 | var runnable = runnableLookupTable[runnablesToRun[i]]; |
||
541 | allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable)); |
||
542 | } |
||
543 | |||
544 | reporter.jasmineStarted({ |
||
545 | totalSpecsDefined: totalSpecsDefined |
||
546 | }); |
||
547 | |||
548 | queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone}); |
||
549 | }; |
||
550 | |||
551 | this.addReporter = function(reporterToAdd) { |
||
552 | reporter.addReporter(reporterToAdd); |
||
553 | }; |
||
554 | |||
555 | this.addMatchers = function(matchersToAdd) { |
||
556 | j$.Expectation.addMatchers(matchersToAdd); |
||
557 | }; |
||
558 | |||
559 | this.spyOn = function(obj, methodName) { |
||
560 | if (j$.util.isUndefined(obj)) { |
||
561 | throw new Error("spyOn could not find an object to spy upon for " + methodName + "()"); |
||
562 | } |
||
563 | |||
564 | if (j$.util.isUndefined(obj[methodName])) { |
||
565 | throw new Error(methodName + '() method does not exist'); |
||
566 | } |
||
567 | |||
568 | if (obj[methodName] && j$.isSpy(obj[methodName])) { |
||
569 | //TODO?: should this return the current spy? Downside: may cause user confusion about spy state |
||
570 | throw new Error(methodName + ' has already been spied upon'); |
||
571 | } |
||
572 | |||
573 | var spy = j$.createSpy(methodName, obj[methodName]); |
||
574 | |||
575 | spies.push({ |
||
576 | spy: spy, |
||
577 | baseObj: obj, |
||
578 | methodName: methodName, |
||
579 | originalValue: obj[methodName] |
||
580 | }); |
||
581 | |||
582 | obj[methodName] = spy; |
||
583 | |||
584 | return spy; |
||
585 | }; |
||
586 | |||
587 | var suiteFactory = function(description) { |
||
588 | var suite = new j$.Suite({ |
||
589 | env: self, |
||
590 | id: getNextSuiteId(), |
||
591 | description: description, |
||
592 | parentSuite: currentSuite, |
||
593 | queueRunner: queueRunnerFactory, |
||
594 | onStart: suiteStarted, |
||
595 | resultCallback: function(attrs) { |
||
596 | reporter.suiteDone(attrs); |
||
597 | } |
||
598 | }); |
||
599 | |||
600 | runnableLookupTable[suite.id] = suite; |
||
601 | return suite; |
||
602 | }; |
||
603 | |||
604 | this.describe = function(description, specDefinitions) { |
||
605 | var suite = suiteFactory(description); |
||
606 | |||
607 | var parentSuite = currentSuite; |
||
608 | parentSuite.addChild(suite); |
||
609 | currentSuite = suite; |
||
610 | |||
611 | var declarationError = null; |
||
612 | try { |
||
613 | specDefinitions.call(suite); |
||
614 | } catch (e) { |
||
615 | declarationError = e; |
||
616 | } |
||
617 | |||
618 | if (declarationError) { |
||
619 | this.it("encountered a declaration exception", function() { |
||
620 | throw declarationError; |
||
621 | }); |
||
622 | } |
||
623 | |||
624 | currentSuite = parentSuite; |
||
625 | |||
626 | return suite; |
||
627 | }; |
||
628 | |||
629 | this.xdescribe = function(description, specDefinitions) { |
||
630 | var suite = this.describe(description, specDefinitions); |
||
631 | suite.disable(); |
||
632 | return suite; |
||
633 | }; |
||
634 | |||
635 | var specFactory = function(description, fn, suite) { |
||
636 | totalSpecsDefined++; |
||
637 | |||
638 | var spec = new j$.Spec({ |
||
639 | id: getNextSpecId(), |
||
640 | beforeFns: beforeFns(suite), |
||
641 | afterFns: afterFns(suite), |
||
642 | expectationFactory: expectationFactory, |
||
643 | exceptionFormatter: exceptionFormatter, |
||
644 | resultCallback: specResultCallback, |
||
645 | getSpecName: function(spec) { |
||
646 | return getSpecName(spec, suite); |
||
647 | }, |
||
648 | onStart: specStarted, |
||
649 | description: description, |
||
650 | expectationResultFactory: expectationResultFactory, |
||
651 | queueRunnerFactory: queueRunnerFactory, |
||
652 | fn: fn, |
||
653 | timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout} |
||
654 | }); |
||
655 | |||
656 | runnableLookupTable[spec.id] = spec; |
||
657 | |||
658 | if (!self.specFilter(spec)) { |
||
659 | spec.disable(); |
||
660 | } |
||
661 | |||
662 | return spec; |
||
663 | |||
664 | function removeAllSpies() { |
||
665 | for (var i = 0; i < spies.length; i++) { |
||
666 | var spyEntry = spies[i]; |
||
667 | spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue; |
||
668 | } |
||
669 | spies = []; |
||
670 | } |
||
671 | |||
672 | function specResultCallback(result) { |
||
673 | removeAllSpies(); |
||
674 | j$.Expectation.resetMatchers(); |
||
675 | customEqualityTesters = []; |
||
676 | currentSpec = null; |
||
677 | reporter.specDone(result); |
||
678 | } |
||
679 | }; |
||
680 | |||
681 | var suiteStarted = function(suite) { |
||
682 | reporter.suiteStarted(suite.result); |
||
683 | }; |
||
684 | |||
685 | this.it = function(description, fn) { |
||
686 | var spec = specFactory(description, fn, currentSuite); |
||
687 | currentSuite.addChild(spec); |
||
688 | return spec; |
||
689 | }; |
||
690 | |||
691 | this.xit = function(description, fn) { |
||
692 | var spec = this.it(description, fn); |
||
693 | spec.pend(); |
||
694 | return spec; |
||
695 | }; |
||
696 | |||
697 | this.expect = function(actual) { |
||
698 | return currentSpec.expect(actual); |
||
699 | }; |
||
700 | |||
701 | this.beforeEach = function(beforeEachFunction) { |
||
702 | currentSuite.beforeEach(beforeEachFunction); |
||
703 | }; |
||
704 | |||
705 | this.afterEach = function(afterEachFunction) { |
||
706 | currentSuite.afterEach(afterEachFunction); |
||
707 | }; |
||
708 | |||
709 | this.pending = function() { |
||
710 | throw j$.Spec.pendingSpecExceptionMessage; |
||
711 | }; |
||
712 | } |
||
713 | |||
714 | return Env; |
||
715 | }; |
||
716 | |||
717 | getJasmineRequireObj().JsApiReporter = function() { |
||
718 | |||
719 | var noopTimer = { |
||
720 | start: function(){}, |
||
721 | elapsed: function(){ return 0; } |
||
722 | }; |
||
723 | |||
724 | function JsApiReporter(options) { |
||
725 | var timer = options.timer || noopTimer, |
||
726 | status = "loaded"; |
||
727 | |||
728 | this.started = false; |
||
729 | this.finished = false; |
||
730 | |||
731 | this.jasmineStarted = function() { |
||
732 | this.started = true; |
||
733 | status = 'started'; |
||
734 | timer.start(); |
||
735 | }; |
||
736 | |||
737 | var executionTime; |
||
738 | |||
739 | this.jasmineDone = function() { |
||
740 | this.finished = true; |
||
741 | executionTime = timer.elapsed(); |
||
742 | status = 'done'; |
||
743 | }; |
||
744 | |||
745 | this.status = function() { |
||
746 | return status; |
||
747 | }; |
||
748 | |||
749 | var suites = {}; |
||
750 | |||
751 | this.suiteStarted = function(result) { |
||
752 | storeSuite(result); |
||
753 | }; |
||
754 | |||
755 | this.suiteDone = function(result) { |
||
756 | storeSuite(result); |
||
757 | }; |
||
758 | |||
759 | function storeSuite(result) { |
||
760 | suites[result.id] = result; |
||
761 | } |
||
762 | |||
763 | this.suites = function() { |
||
764 | return suites; |
||
765 | }; |
||
766 | |||
767 | var specs = []; |
||
768 | this.specStarted = function(result) { }; |
||
769 | |||
770 | this.specDone = function(result) { |
||
771 | specs.push(result); |
||
772 | }; |
||
773 | |||
774 | this.specResults = function(index, length) { |
||
775 | return specs.slice(index, index + length); |
||
776 | }; |
||
777 | |||
778 | this.specs = function() { |
||
779 | return specs; |
||
780 | }; |
||
781 | |||
782 | this.executionTime = function() { |
||
783 | return executionTime; |
||
784 | }; |
||
785 | |||
786 | } |
||
787 | |||
788 | return JsApiReporter; |
||
789 | }; |
||
790 | |||
791 | getJasmineRequireObj().Any = function() { |
||
792 | |||
793 | function Any(expectedObject) { |
||
794 | this.expectedObject = expectedObject; |
||
795 | } |
||
796 | |||
797 | Any.prototype.jasmineMatches = function(other) { |
||
798 | if (this.expectedObject == String) { |
||
799 | return typeof other == 'string' || other instanceof String; |
||
800 | } |
||
801 | |||
802 | if (this.expectedObject == Number) { |
||
803 | return typeof other == 'number' || other instanceof Number; |
||
804 | } |
||
805 | |||
806 | if (this.expectedObject == Function) { |
||
807 | return typeof other == 'function' || other instanceof Function; |
||
808 | } |
||
809 | |||
810 | if (this.expectedObject == Object) { |
||
811 | return typeof other == 'object'; |
||
812 | } |
||
813 | |||
814 | if (this.expectedObject == Boolean) { |
||
815 | return typeof other == 'boolean'; |
||
816 | } |
||
817 | |||
818 | return other instanceof this.expectedObject; |
||
819 | }; |
||
820 | |||
821 | Any.prototype.jasmineToString = function() { |
||
822 | return '<jasmine.any(' + this.expectedClass + ')>'; |
||
823 | }; |
||
824 | |||
825 | return Any; |
||
826 | }; |
||
827 | |||
828 | getJasmineRequireObj().CallTracker = function() { |
||
829 | |||
830 | function CallTracker() { |
||
831 | var calls = []; |
||
832 | |||
833 | this.track = function(context) { |
||
834 | calls.push(context); |
||
835 | }; |
||
836 | |||
837 | this.any = function() { |
||
838 | return !!calls.length; |
||
839 | }; |
||
840 | |||
841 | this.count = function() { |
||
842 | return calls.length; |
||
843 | }; |
||
844 | |||
845 | this.argsFor = function(index) { |
||
846 | var call = calls[index]; |
||
847 | return call ? call.args : []; |
||
848 | }; |
||
849 | |||
850 | this.all = function() { |
||
851 | return calls; |
||
852 | }; |
||
853 | |||
854 | this.allArgs = function() { |
||
855 | var callArgs = []; |
||
856 | for(var i = 0; i < calls.length; i++){ |
||
857 | callArgs.push(calls[i].args); |
||
858 | } |
||
859 | |||
860 | return callArgs; |
||
861 | }; |
||
862 | |||
863 | this.first = function() { |
||
864 | return calls[0]; |
||
865 | }; |
||
866 | |||
867 | this.mostRecent = function() { |
||
868 | return calls[calls.length - 1]; |
||
869 | }; |
||
870 | |||
871 | this.reset = function() { |
||
872 | calls = []; |
||
873 | }; |
||
874 | } |
||
875 | |||
876 | return CallTracker; |
||
877 | }; |
||
878 | |||
879 | getJasmineRequireObj().Clock = function() { |
||
880 | function Clock(global, delayedFunctionScheduler) { |
||
881 | var self = this, |
||
882 | realTimingFunctions = { |
||
883 | setTimeout: global.setTimeout, |
||
884 | clearTimeout: global.clearTimeout, |
||
885 | setInterval: global.setInterval, |
||
886 | clearInterval: global.clearInterval |
||
887 | }, |
||
888 | fakeTimingFunctions = { |
||
889 | setTimeout: setTimeout, |
||
890 | clearTimeout: clearTimeout, |
||
891 | setInterval: setInterval, |
||
892 | clearInterval: clearInterval |
||
893 | }, |
||
894 | installed = false, |
||
895 | timer; |
||
896 | |||
897 | self.install = function() { |
||
898 | replace(global, fakeTimingFunctions); |
||
899 | timer = fakeTimingFunctions; |
||
900 | installed = true; |
||
901 | }; |
||
902 | |||
903 | self.uninstall = function() { |
||
904 | delayedFunctionScheduler.reset(); |
||
905 | replace(global, realTimingFunctions); |
||
906 | timer = realTimingFunctions; |
||
907 | installed = false; |
||
908 | }; |
||
909 | |||
910 | self.setTimeout = function(fn, delay, params) { |
||
911 | if (legacyIE()) { |
||
912 | if (arguments.length > 2) { |
||
913 | throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill"); |
||
914 | } |
||
915 | return timer.setTimeout(fn, delay); |
||
916 | } |
||
917 | return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]); |
||
918 | }; |
||
919 | |||
920 | self.setInterval = function(fn, delay, params) { |
||
921 | if (legacyIE()) { |
||
922 | if (arguments.length > 2) { |
||
923 | throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill"); |
||
924 | } |
||
925 | return timer.setInterval(fn, delay); |
||
926 | } |
||
927 | return Function.prototype.apply.apply(timer.setInterval, [global, arguments]); |
||
928 | }; |
||
929 | |||
930 | self.clearTimeout = function(id) { |
||
931 | return Function.prototype.call.apply(timer.clearTimeout, [global, id]); |
||
932 | }; |
||
933 | |||
934 | self.clearInterval = function(id) { |
||
935 | return Function.prototype.call.apply(timer.clearInterval, [global, id]); |
||
936 | }; |
||
937 | |||
938 | self.tick = function(millis) { |
||
939 | if (installed) { |
||
940 | delayedFunctionScheduler.tick(millis); |
||
941 | } else { |
||
942 | throw new Error("Mock clock is not installed, use jasmine.clock().install()"); |
||
943 | } |
||
944 | }; |
||
945 | |||
946 | return self; |
||
947 | |||
948 | function legacyIE() { |
||
949 | //if these methods are polyfilled, apply will be present |
||
950 | return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply; |
||
951 | } |
||
952 | |||
953 | function replace(dest, source) { |
||
954 | for (var prop in source) { |
||
955 | dest[prop] = source[prop]; |
||
956 | } |
||
957 | } |
||
958 | |||
959 | function setTimeout(fn, delay) { |
||
960 | return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2)); |
||
961 | } |
||
962 | |||
963 | function clearTimeout(id) { |
||
964 | return delayedFunctionScheduler.removeFunctionWithId(id); |
||
965 | } |
||
966 | |||
967 | function setInterval(fn, interval) { |
||
968 | return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true); |
||
969 | } |
||
970 | |||
971 | function clearInterval(id) { |
||
972 | return delayedFunctionScheduler.removeFunctionWithId(id); |
||
973 | } |
||
974 | |||
975 | function argSlice(argsObj, n) { |
||
976 | return Array.prototype.slice.call(argsObj, 2); |
||
977 | } |
||
978 | } |
||
979 | |||
980 | return Clock; |
||
981 | }; |
||
982 | |||
983 | getJasmineRequireObj().DelayedFunctionScheduler = function() { |
||
984 | function DelayedFunctionScheduler() { |
||
985 | var self = this; |
||
986 | var scheduledLookup = []; |
||
987 | var scheduledFunctions = {}; |
||
988 | var currentTime = 0; |
||
989 | var delayedFnCount = 0; |
||
990 | |||
991 | self.tick = function(millis) { |
||
992 | millis = millis || 0; |
||
993 | var endTime = currentTime + millis; |
||
994 | |||
995 | runScheduledFunctions(endTime); |
||
996 | currentTime = endTime; |
||
997 | }; |
||
998 | |||
999 | self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) { |
||
1000 | var f; |
||
1001 | if (typeof(funcToCall) === 'string') { |
||
1002 | /* jshint evil: true */ |
||
1003 | f = function() { return eval(funcToCall); }; |
||
1004 | /* jshint evil: false */ |
||
1005 | } else { |
||
1006 | f = funcToCall; |
||
1007 | } |
||
1008 | |||
1009 | millis = millis || 0; |
||
1010 | timeoutKey = timeoutKey || ++delayedFnCount; |
||
1011 | runAtMillis = runAtMillis || (currentTime + millis); |
||
1012 | |||
1013 | var funcToSchedule = { |
||
1014 | runAtMillis: runAtMillis, |
||
1015 | funcToCall: f, |
||
1016 | recurring: recurring, |
||
1017 | params: params, |
||
1018 | timeoutKey: timeoutKey, |
||
1019 | millis: millis |
||
1020 | }; |
||
1021 | |||
1022 | if (runAtMillis in scheduledFunctions) { |
||
1023 | scheduledFunctions[runAtMillis].push(funcToSchedule); |
||
1024 | } else { |
||
1025 | scheduledFunctions[runAtMillis] = [funcToSchedule]; |
||
1026 | scheduledLookup.push(runAtMillis); |
||
1027 | scheduledLookup.sort(function (a, b) { |
||
1028 | return a - b; |
||
1029 | }); |
||
1030 | } |
||
1031 | |||
1032 | return timeoutKey; |
||
1033 | }; |
||
1034 | |||
1035 | self.removeFunctionWithId = function(timeoutKey) { |
||
1036 | for (var runAtMillis in scheduledFunctions) { |
||
1037 | var funcs = scheduledFunctions[runAtMillis]; |
||
1038 | var i = indexOfFirstToPass(funcs, function (func) { |
||
1039 | return func.timeoutKey === timeoutKey; |
||
1040 | }); |
||
1041 | |||
1042 | if (i > -1) { |
||
1043 | if (funcs.length === 1) { |
||
1044 | delete scheduledFunctions[runAtMillis]; |
||
1045 | deleteFromLookup(runAtMillis); |
||
1046 | } else { |
||
1047 | funcs.splice(i, 1); |
||
1048 | } |
||
1049 | |||
1050 | // intervals get rescheduled when executed, so there's never more |
||
1051 | // than a single scheduled function with a given timeoutKey |
||
1052 | break; |
||
1053 | } |
||
1054 | } |
||
1055 | }; |
||
1056 | |||
1057 | self.reset = function() { |
||
1058 | currentTime = 0; |
||
1059 | scheduledLookup = []; |
||
1060 | scheduledFunctions = {}; |
||
1061 | delayedFnCount = 0; |
||
1062 | }; |
||
1063 | |||
1064 | return self; |
||
1065 | |||
1066 | function indexOfFirstToPass(array, testFn) { |
||
1067 | var index = -1; |
||
1068 | |||
1069 | for (var i = 0; i < array.length; ++i) { |
||
1070 | if (testFn(array[i])) { |
||
1071 | index = i; |
||
1072 | break; |
||
1073 | } |
||
1074 | } |
||
1075 | |||
1076 | return index; |
||
1077 | } |
||
1078 | |||
1079 | function deleteFromLookup(key) { |
||
1080 | var value = Number(key); |
||
1081 | var i = indexOfFirstToPass(scheduledLookup, function (millis) { |
||
1082 | return millis === value; |
||
1083 | }); |
||
1084 | |||
1085 | if (i > -1) { |
||
1086 | scheduledLookup.splice(i, 1); |
||
1087 | } |
||
1088 | } |
||
1089 | |||
1090 | function reschedule(scheduledFn) { |
||
1091 | self.scheduleFunction(scheduledFn.funcToCall, |
||
1092 | scheduledFn.millis, |
||
1093 | scheduledFn.params, |
||
1094 | true, |
||
1095 | scheduledFn.timeoutKey, |
||
1096 | scheduledFn.runAtMillis + scheduledFn.millis); |
||
1097 | } |
||
1098 | |||
1099 | function runScheduledFunctions(endTime) { |
||
1100 | if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { |
||
1101 | return; |
||
1102 | } |
||
1103 | |||
1104 | do { |
||
1105 | currentTime = scheduledLookup.shift(); |
||
1106 | |||
1107 | var funcsToRun = scheduledFunctions[currentTime]; |
||
1108 | delete scheduledFunctions[currentTime]; |
||
1109 | |||
1110 | for (var i = 0; i < funcsToRun.length; ++i) { |
||
1111 | var funcToRun = funcsToRun[i]; |
||
1112 | funcToRun.funcToCall.apply(null, funcToRun.params || []); |
||
1113 | |||
1114 | if (funcToRun.recurring) { |
||
1115 | reschedule(funcToRun); |
||
1116 | } |
||
1117 | } |
||
1118 | } while (scheduledLookup.length > 0 && |
||
1119 | // checking first if we're out of time prevents setTimeout(0) |
||
1120 | // scheduled in a funcToRun from forcing an extra iteration |
||
1121 | currentTime !== endTime && |
||
1122 | scheduledLookup[0] <= endTime); |
||
1123 | } |
||
1124 | } |
||
1125 | |||
1126 | return DelayedFunctionScheduler; |
||
1127 | }; |
||
1128 | |||
1129 | getJasmineRequireObj().ExceptionFormatter = function() { |
||
1130 | function ExceptionFormatter() { |
||
1131 | this.message = function(error) { |
||
1132 | var message = error.name + |
||
1133 | ': ' + |
||
1134 | error.message; |
||
1135 | |||
1136 | if (error.fileName || error.sourceURL) { |
||
1137 | message += " in " + (error.fileName || error.sourceURL); |
||
1138 | } |
||
1139 | |||
1140 | if (error.line || error.lineNumber) { |
||
1141 | message += " (line " + (error.line || error.lineNumber) + ")"; |
||
1142 | } |
||
1143 | |||
1144 | return message; |
||
1145 | }; |
||
1146 | |||
1147 | this.stack = function(error) { |
||
1148 | return error ? error.stack : null; |
||
1149 | }; |
||
1150 | } |
||
1151 | |||
1152 | return ExceptionFormatter; |
||
1153 | }; |
||
1154 | |||
1155 | getJasmineRequireObj().Expectation = function() { |
||
1156 | |||
1157 | var matchers = {}; |
||
1158 | |||
1159 | function Expectation(options) { |
||
1160 | this.util = options.util || { buildFailureMessage: function() {} }; |
||
1161 | this.customEqualityTesters = options.customEqualityTesters || []; |
||
1162 | this.actual = options.actual; |
||
1163 | this.addExpectationResult = options.addExpectationResult || function(){}; |
||
1164 | this.isNot = options.isNot; |
||
1165 | |||
1166 | for (var matcherName in matchers) { |
||
1167 | this[matcherName] = matchers[matcherName]; |
||
1168 | } |
||
1169 | } |
||
1170 | |||
1171 | Expectation.prototype.wrapCompare = function(name, matcherFactory) { |
||
1172 | return function() { |
||
1173 | var args = Array.prototype.slice.call(arguments, 0), |
||
1174 | expected = args.slice(0), |
||
1175 | message = ""; |
||
1176 | |||
1177 | args.unshift(this.actual); |
||
1178 | |||
1179 | var matcher = matcherFactory(this.util, this.customEqualityTesters), |
||
1180 | matcherCompare = matcher.compare; |
||
1181 | |||
1182 | function defaultNegativeCompare() { |
||
1183 | var result = matcher.compare.apply(null, args); |
||
1184 | result.pass = !result.pass; |
||
1185 | return result; |
||
1186 | } |
||
1187 | |||
1188 | if (this.isNot) { |
||
1189 | matcherCompare = matcher.negativeCompare || defaultNegativeCompare; |
||
1190 | } |
||
1191 | |||
1192 | var result = matcherCompare.apply(null, args); |
||
1193 | |||
1194 | if (!result.pass) { |
||
1195 | if (!result.message) { |
||
1196 | args.unshift(this.isNot); |
||
1197 | args.unshift(name); |
||
1198 | message = this.util.buildFailureMessage.apply(null, args); |
||
1199 | } else { |
||
1200 | message = result.message; |
||
1201 | } |
||
1202 | } |
||
1203 | |||
1204 | if (expected.length == 1) { |
||
1205 | expected = expected[0]; |
||
1206 | } |
||
1207 | |||
1208 | // TODO: how many of these params are needed? |
||
1209 | this.addExpectationResult( |
||
1210 | result.pass, |
||
1211 | { |
||
1212 | matcherName: name, |
||
1213 | passed: result.pass, |
||
1214 | message: message, |
||
1215 | actual: this.actual, |
||
1216 | expected: expected // TODO: this may need to be arrayified/sliced |
||
1217 | } |
||
1218 | ); |
||
1219 | }; |
||
1220 | }; |
||
1221 | |||
1222 | Expectation.addCoreMatchers = function(matchers) { |
||
1223 | var prototype = Expectation.prototype; |
||
1224 | for (var matcherName in matchers) { |
||
1225 | var matcher = matchers[matcherName]; |
||
1226 | prototype[matcherName] = prototype.wrapCompare(matcherName, matcher); |
||
1227 | } |
||
1228 | }; |
||
1229 | |||
1230 | Expectation.addMatchers = function(matchersToAdd) { |
||
1231 | for (var name in matchersToAdd) { |
||
1232 | var matcher = matchersToAdd[name]; |
||
1233 | matchers[name] = Expectation.prototype.wrapCompare(name, matcher); |
||
1234 | } |
||
1235 | }; |
||
1236 | |||
1237 | Expectation.resetMatchers = function() { |
||
1238 | for (var name in matchers) { |
||
1239 | delete matchers[name]; |
||
1240 | } |
||
1241 | }; |
||
1242 | |||
1243 | Expectation.Factory = function(options) { |
||
1244 | options = options || {}; |
||
1245 | |||
1246 | var expect = new Expectation(options); |
||
1247 | |||
1248 | // TODO: this would be nice as its own Object - NegativeExpectation |
||
1249 | // TODO: copy instead of mutate options |
||
1250 | options.isNot = true; |
||
1251 | expect.not = new Expectation(options); |
||
1252 | |||
1253 | return expect; |
||
1254 | }; |
||
1255 | |||
1256 | return Expectation; |
||
1257 | }; |
||
1258 | |||
1259 | //TODO: expectation result may make more sense as a presentation of an expectation. |
||
1260 | getJasmineRequireObj().buildExpectationResult = function() { |
||
1261 | function buildExpectationResult(options) { |
||
1262 | var messageFormatter = options.messageFormatter || function() {}, |
||
1263 | stackFormatter = options.stackFormatter || function() {}; |
||
1264 | |||
1265 | return { |
||
1266 | matcherName: options.matcherName, |
||
1267 | expected: options.expected, |
||
1268 | actual: options.actual, |
||
1269 | message: message(), |
||
1270 | stack: stack(), |
||
1271 | passed: options.passed |
||
1272 | }; |
||
1273 | |||
1274 | function message() { |
||
1275 | if (options.passed) { |
||
1276 | return "Passed."; |
||
1277 | } else if (options.message) { |
||
1278 | return options.message; |
||
1279 | } else if (options.error) { |
||
1280 | return messageFormatter(options.error); |
||
1281 | } |
||
1282 | return ""; |
||
1283 | } |
||
1284 | |||
1285 | function stack() { |
||
1286 | if (options.passed) { |
||
1287 | return ""; |
||
1288 | } |
||
1289 | |||
1290 | var error = options.error; |
||
1291 | if (!error) { |
||
1292 | try { |
||
1293 | throw new Error(message()); |
||
1294 | } catch (e) { |
||
1295 | error = e; |
||
1296 | } |
||
1297 | } |
||
1298 | return stackFormatter(error); |
||
1299 | } |
||
1300 | } |
||
1301 | |||
1302 | return buildExpectationResult; |
||
1303 | }; |
||
1304 | |||
1305 | getJasmineRequireObj().ObjectContaining = function(j$) { |
||
1306 | |||
1307 | function ObjectContaining(sample) { |
||
1308 | this.sample = sample; |
||
1309 | } |
||
1310 | |||
1311 | ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) { |
||
1312 | if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); } |
||
1313 | |||
1314 | mismatchKeys = mismatchKeys || []; |
||
1315 | mismatchValues = mismatchValues || []; |
||
1316 | |||
1317 | var hasKey = function(obj, keyName) { |
||
1318 | return obj !== null && !j$.util.isUndefined(obj[keyName]); |
||
1319 | }; |
||
1320 | |||
1321 | for (var property in this.sample) { |
||
1322 | if (!hasKey(other, property) && hasKey(this.sample, property)) { |
||
1323 | mismatchKeys.push("expected has key '" + property + "', but missing from actual."); |
||
1324 | } |
||
1325 | else if (!j$.matchersUtil.equals(this.sample[property], other[property])) { |
||
1326 | mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected."); |
||
1327 | } |
||
1328 | } |
||
1329 | |||
1330 | return (mismatchKeys.length === 0 && mismatchValues.length === 0); |
||
1331 | }; |
||
1332 | |||
1333 | ObjectContaining.prototype.jasmineToString = function() { |
||
1334 | return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>"; |
||
1335 | }; |
||
1336 | |||
1337 | return ObjectContaining; |
||
1338 | }; |
||
1339 | |||
1340 | getJasmineRequireObj().pp = function(j$) { |
||
1341 | |||
1342 | function PrettyPrinter() { |
||
1343 | this.ppNestLevel_ = 0; |
||
1344 | } |
||
1345 | |||
1346 | PrettyPrinter.prototype.format = function(value) { |
||
1347 | this.ppNestLevel_++; |
||
1348 | try { |
||
1349 | if (j$.util.isUndefined(value)) { |
||
1350 | this.emitScalar('undefined'); |
||
1351 | } else if (value === null) { |
||
1352 | this.emitScalar('null'); |
||
1353 | } else if (value === j$.getGlobal()) { |
||
1354 | this.emitScalar('<global>'); |
||
1355 | } else if (value.jasmineToString) { |
||
1356 | this.emitScalar(value.jasmineToString()); |
||
1357 | } else if (typeof value === 'string') { |
||
1358 | this.emitString(value); |
||
1359 | } else if (j$.isSpy(value)) { |
||
1360 | this.emitScalar("spy on " + value.and.identity()); |
||
1361 | } else if (value instanceof RegExp) { |
||
1362 | this.emitScalar(value.toString()); |
||
1363 | } else if (typeof value === 'function') { |
||
1364 | this.emitScalar('Function'); |
||
1365 | } else if (typeof value.nodeType === 'number') { |
||
1366 | this.emitScalar('HTMLNode'); |
||
1367 | } else if (value instanceof Date) { |
||
1368 | this.emitScalar('Date(' + value + ')'); |
||
1369 | } else if (value.__Jasmine_been_here_before__) { |
||
1370 | this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>'); |
||
1371 | } else if (j$.isArray_(value) || j$.isA_('Object', value)) { |
||
1372 | value.__Jasmine_been_here_before__ = true; |
||
1373 | if (j$.isArray_(value)) { |
||
1374 | this.emitArray(value); |
||
1375 | } else { |
||
1376 | this.emitObject(value); |
||
1377 | } |
||
1378 | delete value.__Jasmine_been_here_before__; |
||
1379 | } else { |
||
1380 | this.emitScalar(value.toString()); |
||
1381 | } |
||
1382 | } finally { |
||
1383 | this.ppNestLevel_--; |
||
1384 | } |
||
1385 | }; |
||
1386 | |||
1387 | PrettyPrinter.prototype.iterateObject = function(obj, fn) { |
||
1388 | for (var property in obj) { |
||
1389 | if (!obj.hasOwnProperty(property)) { continue; } |
||
1390 | if (property == '__Jasmine_been_here_before__') { continue; } |
||
1391 | fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) && |
||
1392 | obj.__lookupGetter__(property) !== null) : false); |
||
1393 | } |
||
1394 | }; |
||
1395 | |||
1396 | PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_; |
||
1397 | PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_; |
||
1398 | PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_; |
||
1399 | PrettyPrinter.prototype.emitString = j$.unimplementedMethod_; |
||
1400 | |||
1401 | function StringPrettyPrinter() { |
||
1402 | PrettyPrinter.call(this); |
||
1403 | |||
1404 | this.string = ''; |
||
1405 | } |
||
1406 | |||
1407 | j$.util.inherit(StringPrettyPrinter, PrettyPrinter); |
||
1408 | |||
1409 | StringPrettyPrinter.prototype.emitScalar = function(value) { |
||
1410 | this.append(value); |
||
1411 | }; |
||
1412 | |||
1413 | StringPrettyPrinter.prototype.emitString = function(value) { |
||
1414 | this.append("'" + value + "'"); |
||
1415 | }; |
||
1416 | |||
1417 | StringPrettyPrinter.prototype.emitArray = function(array) { |
||
1418 | if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { |
||
1419 | this.append("Array"); |
||
1420 | return; |
||
1421 | } |
||
1422 | |||
1423 | this.append('[ '); |
||
1424 | for (var i = 0; i < array.length; i++) { |
||
1425 | if (i > 0) { |
||
1426 | this.append(', '); |
||
1427 | } |
||
1428 | this.format(array[i]); |
||
1429 | } |
||
1430 | this.append(' ]'); |
||
1431 | }; |
||
1432 | |||
1433 | StringPrettyPrinter.prototype.emitObject = function(obj) { |
||
1434 | if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { |
||
1435 | this.append("Object"); |
||
1436 | return; |
||
1437 | } |
||
1438 | |||
1439 | var self = this; |
||
1440 | this.append('{ '); |
||
1441 | var first = true; |
||
1442 | |||
1443 | this.iterateObject(obj, function(property, isGetter) { |
||
1444 | if (first) { |
||
1445 | first = false; |
||
1446 | } else { |
||
1447 | self.append(', '); |
||
1448 | } |
||
1449 | |||
1450 | self.append(property); |
||
1451 | self.append(' : '); |
||
1452 | if (isGetter) { |
||
1453 | self.append('<getter>'); |
||
1454 | } else { |
||
1455 | self.format(obj[property]); |
||
1456 | } |
||
1457 | }); |
||
1458 | |||
1459 | this.append(' }'); |
||
1460 | }; |
||
1461 | |||
1462 | StringPrettyPrinter.prototype.append = function(value) { |
||
1463 | this.string += value; |
||
1464 | }; |
||
1465 | |||
1466 | return function(value) { |
||
1467 | var stringPrettyPrinter = new StringPrettyPrinter(); |
||
1468 | stringPrettyPrinter.format(value); |
||
1469 | return stringPrettyPrinter.string; |
||
1470 | }; |
||
1471 | }; |
||
1472 | |||
1473 | getJasmineRequireObj().QueueRunner = function() { |
||
1474 | |||
1475 | function QueueRunner(attrs) { |
||
1476 | this.fns = attrs.fns || []; |
||
1477 | this.onComplete = attrs.onComplete || function() {}; |
||
1478 | this.clearStack = attrs.clearStack || function(fn) {fn();}; |
||
1479 | this.onException = attrs.onException || function() {}; |
||
1480 | this.catchException = attrs.catchException || function() { return true; }; |
||
1481 | this.userContext = {}; |
||
1482 | } |
||
1483 | |||
1484 | QueueRunner.prototype.execute = function() { |
||
1485 | this.run(this.fns, 0); |
||
1486 | }; |
||
1487 | |||
1488 | QueueRunner.prototype.run = function(fns, recursiveIndex) { |
||
1489 | var length = fns.length, |
||
1490 | self = this, |
||
1491 | iterativeIndex; |
||
1492 | |||
1493 | for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { |
||
1494 | var fn = fns[iterativeIndex]; |
||
1495 | if (fn.length > 0) { |
||
1496 | return attemptAsync(fn); |
||
1497 | } else { |
||
1498 | attemptSync(fn); |
||
1499 | } |
||
1500 | } |
||
1501 | |||
1502 | var runnerDone = iterativeIndex >= length; |
||
1503 | |||
1504 | if (runnerDone) { |
||
1505 | this.clearStack(this.onComplete); |
||
1506 | } |
||
1507 | |||
1508 | function attemptSync(fn) { |
||
1509 | try { |
||
1510 | fn.call(self.userContext); |
||
1511 | } catch (e) { |
||
1512 | handleException(e); |
||
1513 | } |
||
1514 | } |
||
1515 | |||
1516 | function attemptAsync(fn) { |
||
1517 | var next = function () { self.run(fns, iterativeIndex + 1); }; |
||
1518 | |||
1519 | try { |
||
1520 | fn.call(self.userContext, next); |
||
1521 | } catch (e) { |
||
1522 | handleException(e); |
||
1523 | next(); |
||
1524 | } |
||
1525 | } |
||
1526 | |||
1527 | function handleException(e) { |
||
1528 | self.onException(e); |
||
1529 | if (!self.catchException(e)) { |
||
1530 | //TODO: set a var when we catch an exception and |
||
1531 | //use a finally block to close the loop in a nice way.. |
||
1532 | throw e; |
||
1533 | } |
||
1534 | } |
||
1535 | }; |
||
1536 | |||
1537 | return QueueRunner; |
||
1538 | }; |
||
1539 | |||
1540 | getJasmineRequireObj().ReportDispatcher = function() { |
||
1541 | function ReportDispatcher(methods) { |
||
1542 | |||
1543 | var dispatchedMethods = methods || []; |
||
1544 | |||
1545 | for (var i = 0; i < dispatchedMethods.length; i++) { |
||
1546 | var method = dispatchedMethods[i]; |
||
1547 | this[method] = (function(m) { |
||
1548 | return function() { |
||
1549 | dispatch(m, arguments); |
||
1550 | }; |
||
1551 | }(method)); |
||
1552 | } |
||
1553 | |||
1554 | var reporters = []; |
||
1555 | |||
1556 | this.addReporter = function(reporter) { |
||
1557 | reporters.push(reporter); |
||
1558 | }; |
||
1559 | |||
1560 | return this; |
||
1561 | |||
1562 | function dispatch(method, args) { |
||
1563 | for (var i = 0; i < reporters.length; i++) { |
||
1564 | var reporter = reporters[i]; |
||
1565 | if (reporter[method]) { |
||
1566 | reporter[method].apply(reporter, args); |
||
1567 | } |
||
1568 | } |
||
1569 | } |
||
1570 | } |
||
1571 | |||
1572 | return ReportDispatcher; |
||
1573 | }; |
||
1574 | |||
1575 | |||
1576 | getJasmineRequireObj().SpyStrategy = function() { |
||
1577 | |||
1578 | function SpyStrategy(options) { |
||
1579 | options = options || {}; |
||
1580 | |||
1581 | var identity = options.name || "unknown", |
||
1582 | originalFn = options.fn || function() {}, |
||
1583 | getSpy = options.getSpy || function() {}, |
||
1584 | plan = function() {}; |
||
1585 | |||
1586 | this.identity = function() { |
||
1587 | return identity; |
||
1588 | }; |
||
1589 | |||
1590 | this.exec = function() { |
||
1591 | return plan.apply(this, arguments); |
||
1592 | }; |
||
1593 | |||
1594 | this.callThrough = function() { |
||
1595 | plan = originalFn; |
||
1596 | return getSpy(); |
||
1597 | }; |
||
1598 | |||
1599 | this.returnValue = function(value) { |
||
1600 | plan = function() { |
||
1601 | return value; |
||
1602 | }; |
||
1603 | return getSpy(); |
||
1604 | }; |
||
1605 | |||
1606 | this.throwError = function(something) { |
||
1607 | var error = (something instanceof Error) ? something : new Error(something); |
||
1608 | plan = function() { |
||
1609 | throw error; |
||
1610 | }; |
||
1611 | return getSpy(); |
||
1612 | }; |
||
1613 | |||
1614 | this.callFake = function(fn) { |
||
1615 | plan = fn; |
||
1616 | return getSpy(); |
||
1617 | }; |
||
1618 | |||
1619 | this.stub = function(fn) { |
||
1620 | plan = function() {}; |
||
1621 | return getSpy(); |
||
1622 | }; |
||
1623 | } |
||
1624 | |||
1625 | return SpyStrategy; |
||
1626 | }; |
||
1627 | |||
1628 | getJasmineRequireObj().Suite = function() { |
||
1629 | function Suite(attrs) { |
||
1630 | this.env = attrs.env; |
||
1631 | this.id = attrs.id; |
||
1632 | this.parentSuite = attrs.parentSuite; |
||
1633 | this.description = attrs.description; |
||
1634 | this.onStart = attrs.onStart || function() {}; |
||
1635 | this.resultCallback = attrs.resultCallback || function() {}; |
||
1636 | this.clearStack = attrs.clearStack || function(fn) {fn();}; |
||
1637 | |||
1638 | this.beforeFns = []; |
||
1639 | this.afterFns = []; |
||
1640 | this.queueRunner = attrs.queueRunner || function() {}; |
||
1641 | this.disabled = false; |
||
1642 | |||
1643 | this.children = []; |
||
1644 | |||
1645 | this.result = { |
||
1646 | id: this.id, |
||
1647 | status: this.disabled ? 'disabled' : '', |
||
1648 | description: this.description, |
||
1649 | fullName: this.getFullName() |
||
1650 | }; |
||
1651 | } |
||
1652 | |||
1653 | Suite.prototype.getFullName = function() { |
||
1654 | var fullName = this.description; |
||
1655 | for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { |
||
1656 | if (parentSuite.parentSuite) { |
||
1657 | fullName = parentSuite.description + ' ' + fullName; |
||
1658 | } |
||
1659 | } |
||
1660 | return fullName; |
||
1661 | }; |
||
1662 | |||
1663 | Suite.prototype.disable = function() { |
||
1664 | this.disabled = true; |
||
1665 | }; |
||
1666 | |||
1667 | Suite.prototype.beforeEach = function(fn) { |
||
1668 | this.beforeFns.unshift(fn); |
||
1669 | }; |
||
1670 | |||
1671 | Suite.prototype.afterEach = function(fn) { |
||
1672 | this.afterFns.unshift(fn); |
||
1673 | }; |
||
1674 | |||
1675 | Suite.prototype.addChild = function(child) { |
||
1676 | this.children.push(child); |
||
1677 | }; |
||
1678 | |||
1679 | Suite.prototype.execute = function(onComplete) { |
||
1680 | var self = this; |
||
1681 | if (this.disabled) { |
||
1682 | complete(); |
||
1683 | return; |
||
1684 | } |
||
1685 | |||
1686 | var allFns = []; |
||
1687 | |||
1688 | for (var i = 0; i < this.children.length; i++) { |
||
1689 | allFns.push(wrapChildAsAsync(this.children[i])); |
||
1690 | } |
||
1691 | |||
1692 | this.onStart(this); |
||
1693 | |||
1694 | this.queueRunner({ |
||
1695 | fns: allFns, |
||
1696 | onComplete: complete |
||
1697 | }); |
||
1698 | |||
1699 | function complete() { |
||
1700 | self.resultCallback(self.result); |
||
1701 | |||
1702 | if (onComplete) { |
||
1703 | onComplete(); |
||
1704 | } |
||
1705 | } |
||
1706 | |||
1707 | function wrapChildAsAsync(child) { |
||
1708 | return function(done) { child.execute(done); }; |
||
1709 | } |
||
1710 | }; |
||
1711 | |||
1712 | return Suite; |
||
1713 | }; |
||
1714 | |||
1715 | if (typeof window == void 0 && typeof exports == "object") { |
||
1716 | exports.Suite = jasmineRequire.Suite; |
||
1717 | } |
||
1718 | |||
1719 | getJasmineRequireObj().Timer = function() { |
||
1720 | function Timer(options) { |
||
1721 | options = options || {}; |
||
1722 | |||
1723 | var now = options.now || function() { return new Date().getTime(); }, |
||
1724 | startTime; |
||
1725 | |||
1726 | this.start = function() { |
||
1727 | startTime = now(); |
||
1728 | }; |
||
1729 | |||
1730 | this.elapsed = function() { |
||
1731 | return now() - startTime; |
||
1732 | }; |
||
1733 | } |
||
1734 | |||
1735 | return Timer; |
||
1736 | }; |
||
1737 | |||
1738 | getJasmineRequireObj().matchersUtil = function(j$) { |
||
1739 | // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? |
||
1740 | |||
1741 | return { |
||
1742 | equals: function(a, b, customTesters) { |
||
1743 | customTesters = customTesters || []; |
||
1744 | |||
1745 | return eq(a, b, [], [], customTesters); |
||
1746 | }, |
||
1747 | |||
1748 | contains: function(haystack, needle, customTesters) { |
||
1749 | customTesters = customTesters || []; |
||
1750 | |||
1751 | if (Object.prototype.toString.apply(haystack) === "[object Array]") { |
||
1752 | for (var i = 0; i < haystack.length; i++) { |
||
1753 | if (eq(haystack[i], needle, [], [], customTesters)) { |
||
1754 | return true; |
||
1755 | } |
||
1756 | } |
||
1757 | return false; |
||
1758 | } |
||
1759 | return haystack.indexOf(needle) >= 0; |
||
1760 | }, |
||
1761 | |||
1762 | buildFailureMessage: function() { |
||
1763 | var args = Array.prototype.slice.call(arguments, 0), |
||
1764 | matcherName = args[0], |
||
1765 | isNot = args[1], |
||
1766 | actual = args[2], |
||
1767 | expected = args.slice(3), |
||
1768 | englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); |
||
1769 | |||
1770 | var message = "Expected " + |
||
1771 | j$.pp(actual) + |
||
1772 | (isNot ? " not " : " ") + |
||
1773 | englishyPredicate; |
||
1774 | |||
1775 | if (expected.length > 0) { |
||
1776 | for (var i = 0; i < expected.length; i++) { |
||
1777 | if (i > 0) { |
||
1778 | message += ","; |
||
1779 | } |
||
1780 | message += " " + j$.pp(expected[i]); |
||
1781 | } |
||
1782 | } |
||
1783 | |||
1784 | return message + "."; |
||
1785 | } |
||
1786 | }; |
||
1787 | |||
1788 | // Equality function lovingly adapted from isEqual in |
||
1789 | // [Underscore](http://underscorejs.org) |
||
1790 | function eq(a, b, aStack, bStack, customTesters) { |
||
1791 | var result = true; |
||
1792 | |||
1793 | for (var i = 0; i < customTesters.length; i++) { |
||
1794 | var customTesterResult = customTesters[i](a, b); |
||
1795 | if (!j$.util.isUndefined(customTesterResult)) { |
||
1796 | return customTesterResult; |
||
1797 | } |
||
1798 | } |
||
1799 | |||
1800 | if (a instanceof j$.Any) { |
||
1801 | result = a.jasmineMatches(b); |
||
1802 | if (result) { |
||
1803 | return true; |
||
1804 | } |
||
1805 | } |
||
1806 | |||
1807 | if (b instanceof j$.Any) { |
||
1808 | result = b.jasmineMatches(a); |
||
1809 | if (result) { |
||
1810 | return true; |
||
1811 | } |
||
1812 | } |
||
1813 | |||
1814 | if (b instanceof j$.ObjectContaining) { |
||
1815 | result = b.jasmineMatches(a); |
||
1816 | if (result) { |
||
1817 | return true; |
||
1818 | } |
||
1819 | } |
||
1820 | |||
1821 | if (a instanceof Error && b instanceof Error) { |
||
1822 | return a.message == b.message; |
||
1823 | } |
||
1824 | |||
1825 | // Identical objects are equal. `0 === -0`, but they aren't identical. |
||
1826 | // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). |
||
1827 | if (a === b) { return a !== 0 || 1 / a == 1 / b; } |
||
1828 | // A strict comparison is necessary because `null == undefined`. |
||
1829 | if (a === null || b === null) { return a === b; } |
||
1830 | var className = Object.prototype.toString.call(a); |
||
1831 | if (className != Object.prototype.toString.call(b)) { return false; } |
||
1832 | switch (className) { |
||
1833 | // Strings, numbers, dates, and booleans are compared by value. |
||
1834 | case '[object String]': |
||
1835 | // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is |
||
1836 | // equivalent to `new String("5")`. |
||
1837 | return a == String(b); |
||
1838 | case '[object Number]': |
||
1839 | // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for |
||
1840 | // other numeric values. |
||
1841 | return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b); |
||
1842 | case '[object Date]': |
||
1843 | case '[object Boolean]': |
||
1844 | // Coerce dates and booleans to numeric primitive values. Dates are compared by their |
||
1845 | // millisecond representations. Note that invalid dates with millisecond representations |
||
1846 | // of `NaN` are not equivalent. |
||
1847 | return +a == +b; |
||
1848 | // RegExps are compared by their source patterns and flags. |
||
1849 | case '[object RegExp]': |
||
1850 | return a.source == b.source && |
||
1851 | a.global == b.global && |
||
1852 | a.multiline == b.multiline && |
||
1853 | a.ignoreCase == b.ignoreCase; |
||
1854 | } |
||
1855 | if (typeof a != 'object' || typeof b != 'object') { return false; } |
||
1856 | // Assume equality for cyclic structures. The algorithm for detecting cyclic |
||
1857 | // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. |
||
1858 | var length = aStack.length; |
||
1859 | while (length--) { |
||
1860 | // Linear search. Performance is inversely proportional to the number of |
||
1861 | // unique nested structures. |
||
1862 | if (aStack[length] == a) { return bStack[length] == b; } |
||
1863 | } |
||
1864 | // Add the first object to the stack of traversed objects. |
||
1865 | aStack.push(a); |
||
1866 | bStack.push(b); |
||
1867 | var size = 0; |
||
1868 | // Recursively compare objects and arrays. |
||
1869 | if (className == '[object Array]') { |
||
1870 | // Compare array lengths to determine if a deep comparison is necessary. |
||
1871 | size = a.length; |
||
1872 | result = size == b.length; |
||
1873 | if (result) { |
||
1874 | // Deep compare the contents, ignoring non-numeric properties. |
||
1875 | while (size--) { |
||
1876 | if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; } |
||
1877 | } |
||
1878 | } |
||
1879 | } else { |
||
1880 | // Objects with different constructors are not equivalent, but `Object`s |
||
1881 | // from different frames are. |
||
1882 | var aCtor = a.constructor, bCtor = b.constructor; |
||
1883 | if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) && |
||
1884 | isFunction(bCtor) && (bCtor instanceof bCtor))) { |
||
1885 | return false; |
||
1886 | } |
||
1887 | // Deep compare objects. |
||
1888 | for (var key in a) { |
||
1889 | if (has(a, key)) { |
||
1890 | // Count the expected number of properties. |
||
1891 | size++; |
||
1892 | // Deep compare each member. |
||
1893 | if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; } |
||
1894 | } |
||
1895 | } |
||
1896 | // Ensure that both objects contain the same number of properties. |
||
1897 | if (result) { |
||
1898 | for (key in b) { |
||
1899 | if (has(b, key) && !(size--)) { break; } |
||
1900 | } |
||
1901 | result = !size; |
||
1902 | } |
||
1903 | } |
||
1904 | // Remove the first object from the stack of traversed objects. |
||
1905 | aStack.pop(); |
||
1906 | bStack.pop(); |
||
1907 | |||
1908 | return result; |
||
1909 | |||
1910 | function has(obj, key) { |
||
1911 | return obj.hasOwnProperty(key); |
||
1912 | } |
||
1913 | |||
1914 | function isFunction(obj) { |
||
1915 | return typeof obj === 'function'; |
||
1916 | } |
||
1917 | } |
||
1918 | }; |
||
1919 | |||
1920 | getJasmineRequireObj().toBe = function() { |
||
1921 | function toBe() { |
||
1922 | return { |
||
1923 | compare: function(actual, expected) { |
||
1924 | return { |
||
1925 | pass: actual === expected |
||
1926 | }; |
||
1927 | } |
||
1928 | }; |
||
1929 | } |
||
1930 | |||
1931 | return toBe; |
||
1932 | }; |
||
1933 | |||
1934 | getJasmineRequireObj().toBeCloseTo = function() { |
||
1935 | |||
1936 | function toBeCloseTo() { |
||
1937 | return { |
||
1938 | compare: function(actual, expected, precision) { |
||
1939 | if (precision !== 0) { |
||
1940 | precision = precision || 2; |
||
1941 | } |
||
1942 | |||
1943 | return { |
||
1944 | pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2) |
||
1945 | }; |
||
1946 | } |
||
1947 | }; |
||
1948 | } |
||
1949 | |||
1950 | return toBeCloseTo; |
||
1951 | }; |
||
1952 | |||
1953 | getJasmineRequireObj().toBeDefined = function() { |
||
1954 | function toBeDefined() { |
||
1955 | return { |
||
1956 | compare: function(actual) { |
||
1957 | return { |
||
1958 | pass: (void 0 !== actual) |
||
1959 | }; |
||
1960 | } |
||
1961 | }; |
||
1962 | } |
||
1963 | |||
1964 | return toBeDefined; |
||
1965 | }; |
||
1966 | |||
1967 | getJasmineRequireObj().toBeFalsy = function() { |
||
1968 | function toBeFalsy() { |
||
1969 | return { |
||
1970 | compare: function(actual) { |
||
1971 | return { |
||
1972 | pass: !!!actual |
||
1973 | }; |
||
1974 | } |
||
1975 | }; |
||
1976 | } |
||
1977 | |||
1978 | return toBeFalsy; |
||
1979 | }; |
||
1980 | |||
1981 | getJasmineRequireObj().toBeGreaterThan = function() { |
||
1982 | |||
1983 | function toBeGreaterThan() { |
||
1984 | return { |
||
1985 | compare: function(actual, expected) { |
||
1986 | return { |
||
1987 | pass: actual > expected |
||
1988 | }; |
||
1989 | } |
||
1990 | }; |
||
1991 | } |
||
1992 | |||
1993 | return toBeGreaterThan; |
||
1994 | }; |
||
1995 | |||
1996 | |||
1997 | getJasmineRequireObj().toBeLessThan = function() { |
||
1998 | function toBeLessThan() { |
||
1999 | return { |
||
2000 | |||
2001 | compare: function(actual, expected) { |
||
2002 | return { |
||
2003 | pass: actual < expected> |
||
2004 | < expected };> |
||
2005 | < expected }> |
||
2006 | < expected };> |
||
2007 | < expected }> |
||
2008 | |||
2009 | < expected return toBeLessThan;> |
||
2010 | < expected};> |
||
2011 | < expectedgetJasmineRequireObj().toBeNaN = function(j$) {> |
||
2012 | |||
2013 | < expected function toBeNaN() {> |
||
2014 | < expected return {> |
||
2015 | < expected compare: function(actual) {> |
||
2016 | < expected var result = {> |
||
2017 | < expected pass: (actual !== actual)> |
||
2018 | < expected };> |
||
2019 | |||
2020 | < expected if (result.pass) {> |
||
2021 | < expected result.message = "Expected actual not to be NaN.";> |
||
2022 | < expected } else {> |
||
2023 | < expected result.message = "Expected " + j$.pp(actual) + " to be NaN.";> |
||
2024 | < expected }> |
||
2025 | |||
2026 | < expected return result;> |
||
2027 | < expected }> |
||
2028 | < expected };> |
||
2029 | < expected }> |
||
2030 | |||
2031 | < expected return toBeNaN;> |
||
2032 | < expected};> |
||
2033 | |||
2034 | < expectedgetJasmineRequireObj().toBeNull = function() {> |
||
2035 | |||
2036 | < expected function toBeNull() {> |
||
2037 | < expected return {> |
||
2038 | < expected compare: function(actual) {> |
||
2039 | < expected return {> |
||
2040 | < expected pass: actual === null> |
||
2041 | < expected };> |
||
2042 | < expected }> |
||
2043 | < expected };> |
||
2044 | < expected }> |
||
2045 | |||
2046 | < expected return toBeNull;> |
||
2047 | < expected};> |
||
2048 | |||
2049 | < expectedgetJasmineRequireObj().toBeTruthy = function() {> |
||
2050 | |||
2051 | < expected function toBeTruthy() {> |
||
2052 | < expected return {> |
||
2053 | < expected compare: function(actual) {> |
||
2054 | < expected return {> |
||
2055 | < expected pass: !!actual> |
||
2056 | < expected };> |
||
2057 | < expected }> |
||
2058 | < expected };> |
||
2059 | < expected }> |
||
2060 | |||
2061 | < expected return toBeTruthy;> |
||
2062 | < expected};> |
||
2063 | |||
2064 | < expectedgetJasmineRequireObj().toBeUndefined = function() {> |
||
2065 | |||
2066 | < expected function toBeUndefined() {> |
||
2067 | < expected return {> |
||
2068 | < expected compare: function(actual) {> |
||
2069 | < expected return {> |
||
2070 | < expected pass: void 0 === actual> |
||
2071 | < expected };> |
||
2072 | < expected }> |
||
2073 | < expected };> |
||
2074 | < expected }> |
||
2075 | |||
2076 | < expected return toBeUndefined;> |
||
2077 | < expected};> |
||
2078 | |||
2079 | < expectedgetJasmineRequireObj().toContain = function() {> |
||
2080 | < expected function toContain(util, customEqualityTesters) {> |
||
2081 | < expected customEqualityTesters = customEqualityTesters || [];> |
||
2082 | |||
2083 | < expected return {> |
||
2084 | < expected compare: function(actual, expected) {> |
||
2085 | |||
2086 | < expected return {> |
||
2087 | < expected pass: util.contains(actual, expected, customEqualityTesters)> |
||
2088 | < expected };> |
||
2089 | < expected }> |
||
2090 | < expected };> |
||
2091 | < expected }> |
||
2092 | |||
2093 | < expected return toContain;> |
||
2094 | < expected};> |
||
2095 | |||
2096 | < expectedgetJasmineRequireObj().toEqual = function() {> |
||
2097 | |||
2098 | < expected function toEqual(util, customEqualityTesters) {> |
||
2099 | < expected customEqualityTesters = customEqualityTesters || [];> |
||
2100 | |||
2101 | < expected return {> |
||
2102 | < expected compare: function(actual, expected) {> |
||
2103 | < expected var result = {> |
||
2104 | < expected pass: false> |
||
2105 | < expected };> |
||
2106 | |||
2107 | < expected result.pass = util.equals(actual, expected, customEqualityTesters);> |
||
2108 | |||
2109 | < expected return result;> |
||
2110 | < expected }> |
||
2111 | < expected };> |
||
2112 | < expected }> |
||
2113 | |||
2114 | < expected return toEqual;> |
||
2115 | < expected};> |
||
2116 | |||
2117 | < expectedgetJasmineRequireObj().toHaveBeenCalled = function(j$) {> |
||
2118 | |||
2119 | < expected function toHaveBeenCalled() {> |
||
2120 | < expected return {> |
||
2121 | < expected compare: function(actual) {> |
||
2122 | < expected var result = {};> |
||
2123 | |||
2124 | < expected if (!j$.isSpy(actual)) {> |
||
2125 | < expected throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');> |
||
2126 | < expected }> |
||
2127 | |||
2128 | < expected if (arguments.length > 1) {> |
||
2129 | < expected throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');> |
||
2130 | < expected }> |
||
2131 | |||
2132 | < expected result.pass = actual.calls.any();> |
||
2133 | |||
2134 | < expected result.message = result.pass ?> |
||
2135 | < expected "Expected spy " + actual.and.identity() + " not to have been called." :> |
||
2136 | < expected "Expected spy " + actual.and.identity() + " to have been called.";> |
||
2137 | |||
2138 | < expected return result;> |
||
2139 | < expected }> |
||
2140 | < expected };> |
||
2141 | < expected }> |
||
2142 | |||
2143 | < expected return toHaveBeenCalled;> |
||
2144 | < expected};> |
||
2145 | |||
2146 | < expectedgetJasmineRequireObj().toHaveBeenCalledWith = function(j$) {> |
||
2147 | |||
2148 | < expected function toHaveBeenCalledWith(util) {> |
||
2149 | < expected return {> |
||
2150 | < expected compare: function() {> |
||
2151 | < expected var args = Array.prototype.slice.call(arguments, 0),> |
||
2152 | < expected actual = args[0],> |
||
2153 | < expected expectedArgs = args.slice(1),> |
||
2154 | < expected result = { pass: false };> |
||
2155 | |||
2156 | < expected if (!j$.isSpy(actual)) {> |
||
2157 | < expected throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');> |
||
2158 | < expected }> |
||
2159 | |||
2160 | < expected if (!actual.calls.any()) {> |
||
2161 | < expected result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";> |
||
2162 | < expected return result;> |
||
2163 | < expected }> |
||
2164 | |||
2165 | < expected if (util.contains(actual.calls.allArgs(), expectedArgs)) {> |
||
2166 | < expected result.pass = true;> |
||
2167 | < expected result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";> |
||
2168 | < expected } else {> |
||
2169 | < expected result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";> |
||
2170 | < expected }> |
||
2171 | |||
2172 | < expected return result;> |
||
2173 | < expected }> |
||
2174 | < expected };> |
||
2175 | < expected }> |
||
2176 | |||
2177 | < expected return toHaveBeenCalledWith;> |
||
2178 | < expected};> |
||
2179 | |||
2180 | < expectedgetJasmineRequireObj().toMatch = function() {> |
||
2181 | |||
2182 | < expected function toMatch() {> |
||
2183 | < expected return {> |
||
2184 | < expected compare: function(actual, expected) {> |
||
2185 | < expected var regexp = new RegExp(expected);> |
||
2186 | |||
2187 | < expected return {> |
||
2188 | < expected pass: regexp.test(actual)> |
||
2189 | < expected };> |
||
2190 | < expected }> |
||
2191 | < expected };> |
||
2192 | < expected }> |
||
2193 | |||
2194 | < expected return toMatch;> |
||
2195 | < expected};> |
||
2196 | |||
2197 | < expectedgetJasmineRequireObj().toThrow = function(j$) {> |
||
2198 | |||
2199 | < expected function toThrow(util) {> |
||
2200 | < expected return {> |
||
2201 | < expected compare: function(actual, expected) {> |
||
2202 | < expected var result = { pass: false },> |
||
2203 | < expected threw = false,> |
||
2204 | < expected thrown;> |
||
2205 | |||
2206 | < expected if (typeof actual != "function") {> |
||
2207 | < expected throw new Error("Actual is not a Function");> |
||
2208 | < expected }> |
||
2209 | |||
2210 | < expected try {> |
||
2211 | < expected actual();> |
||
2212 | < expected } catch (e) {> |
||
2213 | < expected threw = true;> |
||
2214 | < expected thrown = e;> |
||
2215 | < expected }> |
||
2216 | |||
2217 | < expected if (!threw) {> |
||
2218 | < expected result.message = "Expected function to throw an exception.";> |
||
2219 | < expected return result;> |
||
2220 | < expected }> |
||
2221 | |||
2222 | < expected if (arguments.length == 1) {> |
||
2223 | < expected result.pass = true;> |
||
2224 | < expected result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";> |
||
2225 | |||
2226 | < expected return result;> |
||
2227 | < expected }> |
||
2228 | |||
2229 | < expected if (util.equals(thrown, expected)) {> |
||
2230 | < expected result.pass = true;> |
||
2231 | < expected result.message = "Expected function not to throw " + j$.pp(expected) + ".";> |
||
2232 | < expected } else {> |
||
2233 | < expected result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";> |
||
2234 | < expected }> |
||
2235 | |||
2236 | < expected return result;> |
||
2237 | < expected }> |
||
2238 | < expected };> |
||
2239 | < expected }> |
||
2240 | |||
2241 | < expected return toThrow;> |
||
2242 | < expected};> |
||
2243 | |||
2244 | < expectedgetJasmineRequireObj().toThrowError = function(j$) {> |
||
2245 | < expected function toThrowError (util) {> |
||
2246 | < expected return {> |
||
2247 | < expected compare: function(actual) {> |
||
2248 | < expected var threw = false,> |
||
2249 | < expected thrown,> |
||
2250 | < expected errorType,> |
||
2251 | < expected message,> |
||
2252 | < expected regexp,> |
||
2253 | < expected name,> |
||
2254 | < expected constructorName;> |
||
2255 | |||
2256 | < expected if (typeof actual != "function") {> |
||
2257 | < expected throw new Error("Actual is not a Function");> |
||
2258 | < expected }> |
||
2259 | |||
2260 | < expected extractExpectedParams.apply(null, arguments);> |
||
2261 | |||
2262 | < expected try {> |
||
2263 | < expected actual();> |
||
2264 | < expected } catch (e) {> |
||
2265 | < expected threw = true;> |
||
2266 | < expected thrown = e;> |
||
2267 | < expected }> |
||
2268 | |||
2269 | < expected if (!threw) {> |
||
2270 | < expected return fail("Expected function to throw an Error.");> |
||
2271 | < expected }> |
||
2272 | |||
2273 | < expected if (!(thrown instanceof Error)) {> |
||
2274 | < expected return fail("Expected function to throw an Error, but it threw " + thrown + ".");> |
||
2275 | < expected }> |
||
2276 | |||
2277 | < expected if (arguments.length == 1) {> |
||
2278 | < expected return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");> |
||
2279 | < expected }> |
||
2280 | |||
2281 | < expected if (errorType) {> |
||
2282 | < expected name = fnNameFor(errorType);> |
||
2283 | < expected constructorName = fnNameFor(thrown.constructor);> |
||
2284 | < expected }> |
||
2285 | |||
2286 | < expected if (errorType && message) {> |
||
2287 | < expected if (thrown.constructor == errorType && util.equals(thrown.message, message)) {> |
||
2288 | < expected return pass("Expected function not to throw " + name + " with message \"" + message + "\".");> |
||
2289 | < expected } else {> |
||
2290 | < expected return fail("Expected function to throw " + name + " with message \"" + message +> |
||
2291 | < expected "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");> |
||
2292 | < expected }> |
||
2293 | < expected }> |
||
2294 | |||
2295 | < expected if (errorType && regexp) {> |
||
2296 | < expected if (thrown.constructor == errorType && regexp.test(thrown.message)) {> |
||
2297 | < expected return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");> |
||
2298 | < expected } else {> |
||
2299 | < expected return fail("Expected function to throw " + name + " with message matching " + regexp +> |
||
2300 | < expected ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");> |
||
2301 | < expected }> |
||
2302 | < expected }> |
||
2303 | |||
2304 | < expected if (errorType) {> |
||
2305 | < expected if (thrown.constructor == errorType) {> |
||
2306 | < expected return pass("Expected function not to throw " + name + ".");> |
||
2307 | < expected } else {> |
||
2308 | < expected return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");> |
||
2309 | < expected }> |
||
2310 | < expected }> |
||
2311 | |||
2312 | < expected if (message) {> |
||
2313 | < expected if (thrown.message == message) {> |
||
2314 | < expected return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");> |
||
2315 | < expected } else {> |
||
2316 | < expected return fail("Expected function to throw an exception with message " + j$.pp(message) +> |
||
2317 | < expected ", but it threw an exception with message " + j$.pp(thrown.message) + ".");> |
||
2318 | < expected }> |
||
2319 | < expected }> |
||
2320 | |||
2321 | < expected if (regexp) {> |
||
2322 | < expected if (regexp.test(thrown.message)) {> |
||
2323 | < expected return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");> |
||
2324 | < expected } else {> |
||
2325 | < expected return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +> |
||
2326 | < expected ", but it threw an exception with message " + j$.pp(thrown.message) + ".");> |
||
2327 | < expected }> |
||
2328 | < expected }> |
||
2329 | |||
2330 | < expected function fnNameFor(func) {> |
||
2331 | < expected return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];> |
||
2332 | < expected }> |
||
2333 | |||
2334 | < expected function pass(notMessage) {> |
||
2335 | < expected return {> |
||
2336 | < expected pass: true,> |
||
2337 | < expected message: notMessage> |
||
2338 | < expected };> |
||
2339 | < expected }> |
||
2340 | |||
2341 | < expected function fail(message) {> |
||
2342 | < expected return {> |
||
2343 | < expected pass: false,> |
||
2344 | < expected message: message> |
||
2345 | < expected };> |
||
2346 | < expected }> |
||
2347 | |||
2348 | < expected function extractExpectedParams() {> |
||
2349 | < expected if (arguments.length == 1) {> |
||
2350 | < expected return;> |
||
2351 | < expected }> |
||
2352 | |||
2353 | < expected if (arguments.length == 2) {> |
||
2354 | < expected var expected = arguments[1];> |
||
2355 | |||
2356 | < expected if (expected instanceof RegExp) {> |
||
2357 | < expected regexp = expected;> |
||
2358 | < expected } else if (typeof expected == "string") {> |
||
2359 | < expected message = expected;> |
||
2360 | < expected } else if (checkForAnErrorType(expected)) {> |
||
2361 | < expected errorType = expected;> |
||
2362 | < expected }> |
||
2363 | |||
2364 | < expected if (!(errorType || message || regexp)) {> |
||
2365 | < expected throw new Error("Expected is not an Error, string, or RegExp.");> |
||
2366 | < expected }> |
||
2367 | < expected } else {> |
||
2368 | < expected if (checkForAnErrorType(arguments[1])) {> |
||
2369 | < expected errorType = arguments[1];> |
||
2370 | < expected } else {> |
||
2371 | < expected throw new Error("Expected error type is not an Error.");> |
||
2372 | < expected }> |
||
2373 | |||
2374 | < expected if (arguments[2] instanceof RegExp) {> |
||
2375 | < expected regexp = arguments[2];> |
||
2376 | < expected } else if (typeof arguments[2] == "string") {> |
||
2377 | < expected message = arguments[2];> |
||
2378 | < expected } else {> |
||
2379 | < expected throw new Error("Expected error message is not a string or RegExp.");> |
||
2380 | < expected }> |
||
2381 | < expected }> |
||
2382 | < expected }> |
||
2383 | |||
2384 | < expected function checkForAnErrorType(type) {> |
||
2385 | < expected if (typeof type !== "function") {> |
||
2386 | < expected return false;> |
||
2387 | < expected }> |
||
2388 | |||
2389 | < expected var Surrogate = function() {};> |
||
2390 | < expected Surrogate.prototype = type.prototype;> |
||
2391 | < expected return (new Surrogate()) instanceof Error;> |
||
2392 | < expected }> |
||
2393 | < expected }> |
||
2394 | < expected };> |
||
2395 | < expected }> |
||
2396 | |||
2397 | < expected return toThrowError;> |
||
2398 | < expected};> |
||
2399 | |||
2400 | < expectedgetJasmineRequireObj().version = function() {> |
||
2401 | < expected return "2.0.0";> |
||
2402 | < expected};> |