scratch – Blame information for rev 133

Subversion Repositories:
Rev:
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, '&amp;')
207 .replace(/g, '&lt;')
208 .replace(/>/g, '&gt;');
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};