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