learn-test 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +23 -0
  6. data/README.md +38 -0
  7. data/Rakefile +2 -0
  8. data/bin/learn-test +78 -0
  9. data/learn-test.gemspec +30 -0
  10. data/lib/learn_test.rb +26 -0
  11. data/lib/learn_test/file_finder.rb +12 -0
  12. data/lib/learn_test/github_interactor.rb +23 -0
  13. data/lib/learn_test/jasmine/boot.js +184 -0
  14. data/lib/learn_test/jasmine/console.js +161 -0
  15. data/lib/learn_test/jasmine/formatters/jasmine2-junit.js +199 -0
  16. data/lib/learn_test/jasmine/helpers/ConsoleHelper.js +12 -0
  17. data/lib/learn_test/jasmine/helpers/ConsoleHelperNoColor.js +12 -0
  18. data/lib/learn_test/jasmine/initializer.rb +27 -0
  19. data/lib/learn_test/jasmine/jasmine-html.js +360 -0
  20. data/lib/learn_test/jasmine/jasmine-jquery.js +813 -0
  21. data/lib/learn_test/jasmine/jasmine.css +56 -0
  22. data/lib/learn_test/jasmine/jasmine.js +2403 -0
  23. data/lib/learn_test/jasmine/jasmine_favicon.png +0 -0
  24. data/lib/learn_test/jasmine/jquery-1.8.0.min.js +2 -0
  25. data/lib/learn_test/jasmine/jquery-ui-1.8.23.custom.min.js +125 -0
  26. data/lib/learn_test/jasmine/phantom_checker.rb +55 -0
  27. data/lib/learn_test/jasmine/runner.rb +129 -0
  28. data/lib/learn_test/jasmine/runners/SpecRunner.html +35 -0
  29. data/lib/learn_test/jasmine/runners/run-jasmine.js +228 -0
  30. data/lib/learn_test/jasmine/templates/SpecRunnerTemplate.html.erb +35 -0
  31. data/lib/learn_test/jasmine/templates/SpecRunnerTemplateNoColor.html.erb +35 -0
  32. data/lib/learn_test/jasmine/templates/requires.yml.example +7 -0
  33. data/lib/learn_test/jasmine/vendor/require.js +2077 -0
  34. data/lib/learn_test/netrc_interactor.rb +18 -0
  35. data/lib/learn_test/python_unittest/nose_installer.rb +35 -0
  36. data/lib/learn_test/python_unittest/requirements_checker.rb +57 -0
  37. data/lib/learn_test/python_unittest/runner.rb +89 -0
  38. data/lib/learn_test/repo_parser.rb +22 -0
  39. data/lib/learn_test/rspec/runner.rb +113 -0
  40. data/lib/learn_test/spec_type_parser.rb +26 -0
  41. data/lib/learn_test/user_id_parser.rb +9 -0
  42. data/lib/learn_test/username_parser.rb +19 -0
  43. data/lib/learn_test/version.rb +3 -0
  44. data/spec/features/jasmine_jquery_fixtures_spec.rb +10 -0
  45. data/spec/features/rspec_unit_spec.rb +10 -0
  46. data/spec/fixtures/jasmine-jquery-fixtures/index.html +10 -0
  47. data/spec/fixtures/jasmine-jquery-fixtures/requires.yml +4 -0
  48. data/spec/fixtures/jasmine-jquery-fixtures/spec/jasmine-jquery-fixtures-spec.js +11 -0
  49. data/spec/fixtures/rspec-unit-spec/.rspec +2 -0
  50. data/spec/fixtures/rspec-unit-spec/lib/dog.rb +2 -0
  51. data/spec/fixtures/rspec-unit-spec/spec/dog_spec.rb +7 -0
  52. data/spec/fixtures/rspec-unit-spec/spec/spec_helper.rb +93 -0
  53. data/spec/repo_parser_spec.rb +25 -0
  54. data/spec/spec_helper.rb +10 -0
  55. metadata +237 -0
@@ -0,0 +1,56 @@
1
+ body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
2
+
3
+ .html-reporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
4
+ .html-reporter a { text-decoration: none; }
5
+ .html-reporter a:hover { text-decoration: underline; }
6
+ .html-reporter p, .html-reporter h1, .html-reporter h2, .html-reporter h3, .html-reporter h4, .html-reporter h5, .html-reporter h6 { margin: 0; line-height: 14px; }
7
+ .html-reporter .banner, .html-reporter .symbol-summary, .html-reporter .summary, .html-reporter .result-message, .html-reporter .spec .description, .html-reporter .spec-detail .description, .html-reporter .alert .bar, .html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; }
8
+ .html-reporter .banner .version { margin-left: 14px; }
9
+ .html-reporter #jasmine_content { position: fixed; right: 100%; }
10
+ .html-reporter .version { color: #aaaaaa; }
11
+ .html-reporter .banner { margin-top: 14px; }
12
+ .html-reporter .duration { color: #aaaaaa; float: right; }
13
+ .html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; }
14
+ .html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; }
15
+ .html-reporter .symbol-summary li.passed { font-size: 14px; }
16
+ .html-reporter .symbol-summary li.passed:before { color: #5e7d00; content: "\02022"; }
17
+ .html-reporter .symbol-summary li.failed { line-height: 9px; }
18
+ .html-reporter .symbol-summary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
19
+ .html-reporter .symbol-summary li.disabled { font-size: 14px; }
20
+ .html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; }
21
+ .html-reporter .symbol-summary li.pending { line-height: 17px; }
22
+ .html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; }
23
+ .html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
24
+ .html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
25
+ .html-reporter .bar.failed { background-color: #b03911; }
26
+ .html-reporter .bar.passed { background-color: #a6b779; }
27
+ .html-reporter .bar.skipped { background-color: #bababa; }
28
+ .html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; }
29
+ .html-reporter .bar.menu a { color: #333333; }
30
+ .html-reporter .bar a { color: white; }
31
+ .html-reporter.spec-list .bar.menu.failure-list, .html-reporter.spec-list .results .failures { display: none; }
32
+ .html-reporter.failure-list .bar.menu.spec-list, .html-reporter.failure-list .summary { display: none; }
33
+ .html-reporter .running-alert { background-color: #666666; }
34
+ .html-reporter .results { margin-top: 14px; }
35
+ .html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
36
+ .html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
37
+ .html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
38
+ .html-reporter.showDetails .summary { display: none; }
39
+ .html-reporter.showDetails #details { display: block; }
40
+ .html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
41
+ .html-reporter .summary { margin-top: 14px; }
42
+ .html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; }
43
+ .html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; }
44
+ .html-reporter .summary li.passed a { color: #5e7d00; }
45
+ .html-reporter .summary li.failed a { color: #b03911; }
46
+ .html-reporter .summary li.pending a { color: #ba9d37; }
47
+ .html-reporter .description + .suite { margin-top: 0; }
48
+ .html-reporter .suite { margin-top: 14px; }
49
+ .html-reporter .suite a { color: #333333; }
50
+ .html-reporter .failures .spec-detail { margin-bottom: 28px; }
51
+ .html-reporter .failures .spec-detail .description { background-color: #b03911; }
52
+ .html-reporter .failures .spec-detail .description a { color: white; }
53
+ .html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; }
54
+ .html-reporter .result-message span.result { display: block; }
55
+ .html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
56
+
@@ -0,0 +1,2403 @@
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
+ };
2005
+ }
2006
+ };
2007
+ }
2008
+
2009
+ return toBeLessThan;
2010
+ };
2011
+ getJasmineRequireObj().toBeNaN = function(j$) {
2012
+
2013
+ function toBeNaN() {
2014
+ return {
2015
+ compare: function(actual) {
2016
+ var result = {
2017
+ pass: (actual !== actual)
2018
+ };
2019
+
2020
+ if (result.pass) {
2021
+ result.message = "Expected actual not to be NaN.";
2022
+ } else {
2023
+ result.message = "Expected " + j$.pp(actual) + " to be NaN.";
2024
+ }
2025
+
2026
+ return result;
2027
+ }
2028
+ };
2029
+ }
2030
+
2031
+ return toBeNaN;
2032
+ };
2033
+
2034
+ getJasmineRequireObj().toBeNull = function() {
2035
+
2036
+ function toBeNull() {
2037
+ return {
2038
+ compare: function(actual) {
2039
+ return {
2040
+ pass: actual === null
2041
+ };
2042
+ }
2043
+ };
2044
+ }
2045
+
2046
+ return toBeNull;
2047
+ };
2048
+
2049
+ getJasmineRequireObj().toBeTruthy = function() {
2050
+
2051
+ function toBeTruthy() {
2052
+ return {
2053
+ compare: function(actual) {
2054
+ return {
2055
+ pass: !!actual
2056
+ };
2057
+ }
2058
+ };
2059
+ }
2060
+
2061
+ return toBeTruthy;
2062
+ };
2063
+
2064
+ getJasmineRequireObj().toBeUndefined = function() {
2065
+
2066
+ function toBeUndefined() {
2067
+ return {
2068
+ compare: function(actual) {
2069
+ return {
2070
+ pass: void 0 === actual
2071
+ };
2072
+ }
2073
+ };
2074
+ }
2075
+
2076
+ return toBeUndefined;
2077
+ };
2078
+
2079
+ getJasmineRequireObj().toContain = function() {
2080
+ function toContain(util, customEqualityTesters) {
2081
+ customEqualityTesters = customEqualityTesters || [];
2082
+
2083
+ return {
2084
+ compare: function(actual, expected) {
2085
+
2086
+ return {
2087
+ pass: util.contains(actual, expected, customEqualityTesters)
2088
+ };
2089
+ }
2090
+ };
2091
+ }
2092
+
2093
+ return toContain;
2094
+ };
2095
+
2096
+ getJasmineRequireObj().toEqual = function() {
2097
+
2098
+ function toEqual(util, customEqualityTesters) {
2099
+ customEqualityTesters = customEqualityTesters || [];
2100
+
2101
+ return {
2102
+ compare: function(actual, expected) {
2103
+ var result = {
2104
+ pass: false
2105
+ };
2106
+
2107
+ result.pass = util.equals(actual, expected, customEqualityTesters);
2108
+
2109
+ return result;
2110
+ }
2111
+ };
2112
+ }
2113
+
2114
+ return toEqual;
2115
+ };
2116
+
2117
+ getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2118
+
2119
+ function toHaveBeenCalled() {
2120
+ return {
2121
+ compare: function(actual) {
2122
+ var result = {};
2123
+
2124
+ if (!j$.isSpy(actual)) {
2125
+ throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
2126
+ }
2127
+
2128
+ if (arguments.length > 1) {
2129
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
2130
+ }
2131
+
2132
+ result.pass = actual.calls.any();
2133
+
2134
+ result.message = result.pass ?
2135
+ "Expected spy " + actual.and.identity() + " not to have been called." :
2136
+ "Expected spy " + actual.and.identity() + " to have been called.";
2137
+
2138
+ return result;
2139
+ }
2140
+ };
2141
+ }
2142
+
2143
+ return toHaveBeenCalled;
2144
+ };
2145
+
2146
+ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2147
+
2148
+ function toHaveBeenCalledWith(util) {
2149
+ return {
2150
+ compare: function() {
2151
+ var args = Array.prototype.slice.call(arguments, 0),
2152
+ actual = args[0],
2153
+ expectedArgs = args.slice(1),
2154
+ result = { pass: false };
2155
+
2156
+ if (!j$.isSpy(actual)) {
2157
+ throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
2158
+ }
2159
+
2160
+ if (!actual.calls.any()) {
2161
+ result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
2162
+ return result;
2163
+ }
2164
+
2165
+ if (util.contains(actual.calls.allArgs(), expectedArgs)) {
2166
+ result.pass = true;
2167
+ result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
2168
+ } else {
2169
+ 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
+ }
2171
+
2172
+ return result;
2173
+ }
2174
+ };
2175
+ }
2176
+
2177
+ return toHaveBeenCalledWith;
2178
+ };
2179
+
2180
+ getJasmineRequireObj().toMatch = function() {
2181
+
2182
+ function toMatch() {
2183
+ return {
2184
+ compare: function(actual, expected) {
2185
+ var regexp = new RegExp(expected);
2186
+
2187
+ return {
2188
+ pass: regexp.test(actual)
2189
+ };
2190
+ }
2191
+ };
2192
+ }
2193
+
2194
+ return toMatch;
2195
+ };
2196
+
2197
+ getJasmineRequireObj().toThrow = function(j$) {
2198
+
2199
+ function toThrow(util) {
2200
+ return {
2201
+ compare: function(actual, expected) {
2202
+ var result = { pass: false },
2203
+ threw = false,
2204
+ thrown;
2205
+
2206
+ if (typeof actual != "function") {
2207
+ throw new Error("Actual is not a Function");
2208
+ }
2209
+
2210
+ try {
2211
+ actual();
2212
+ } catch (e) {
2213
+ threw = true;
2214
+ thrown = e;
2215
+ }
2216
+
2217
+ if (!threw) {
2218
+ result.message = "Expected function to throw an exception.";
2219
+ return result;
2220
+ }
2221
+
2222
+ if (arguments.length == 1) {
2223
+ result.pass = true;
2224
+ result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
2225
+
2226
+ return result;
2227
+ }
2228
+
2229
+ if (util.equals(thrown, expected)) {
2230
+ result.pass = true;
2231
+ result.message = "Expected function not to throw " + j$.pp(expected) + ".";
2232
+ } else {
2233
+ result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";
2234
+ }
2235
+
2236
+ return result;
2237
+ }
2238
+ };
2239
+ }
2240
+
2241
+ return toThrow;
2242
+ };
2243
+
2244
+ getJasmineRequireObj().toThrowError = function(j$) {
2245
+ function toThrowError (util) {
2246
+ return {
2247
+ compare: function(actual) {
2248
+ var threw = false,
2249
+ thrown,
2250
+ errorType,
2251
+ message,
2252
+ regexp,
2253
+ name,
2254
+ constructorName;
2255
+
2256
+ if (typeof actual != "function") {
2257
+ throw new Error("Actual is not a Function");
2258
+ }
2259
+
2260
+ extractExpectedParams.apply(null, arguments);
2261
+
2262
+ try {
2263
+ actual();
2264
+ } catch (e) {
2265
+ threw = true;
2266
+ thrown = e;
2267
+ }
2268
+
2269
+ if (!threw) {
2270
+ return fail("Expected function to throw an Error.");
2271
+ }
2272
+
2273
+ if (!(thrown instanceof Error)) {
2274
+ return fail("Expected function to throw an Error, but it threw " + thrown + ".");
2275
+ }
2276
+
2277
+ if (arguments.length == 1) {
2278
+ return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
2279
+ }
2280
+
2281
+ if (errorType) {
2282
+ name = fnNameFor(errorType);
2283
+ constructorName = fnNameFor(thrown.constructor);
2284
+ }
2285
+
2286
+ if (errorType && message) {
2287
+ if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
2288
+ return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
2289
+ } else {
2290
+ return fail("Expected function to throw " + name + " with message \"" + message +
2291
+ "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2292
+ }
2293
+ }
2294
+
2295
+ if (errorType && regexp) {
2296
+ if (thrown.constructor == errorType && regexp.test(thrown.message)) {
2297
+ return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
2298
+ } else {
2299
+ return fail("Expected function to throw " + name + " with message matching " + regexp +
2300
+ ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2301
+ }
2302
+ }
2303
+
2304
+ if (errorType) {
2305
+ if (thrown.constructor == errorType) {
2306
+ return pass("Expected function not to throw " + name + ".");
2307
+ } else {
2308
+ return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
2309
+ }
2310
+ }
2311
+
2312
+ if (message) {
2313
+ if (thrown.message == message) {
2314
+ return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
2315
+ } else {
2316
+ return fail("Expected function to throw an exception with message " + j$.pp(message) +
2317
+ ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2318
+ }
2319
+ }
2320
+
2321
+ if (regexp) {
2322
+ if (regexp.test(thrown.message)) {
2323
+ return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
2324
+ } else {
2325
+ return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
2326
+ ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2327
+ }
2328
+ }
2329
+
2330
+ function fnNameFor(func) {
2331
+ return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2332
+ }
2333
+
2334
+ function pass(notMessage) {
2335
+ return {
2336
+ pass: true,
2337
+ message: notMessage
2338
+ };
2339
+ }
2340
+
2341
+ function fail(message) {
2342
+ return {
2343
+ pass: false,
2344
+ message: message
2345
+ };
2346
+ }
2347
+
2348
+ function extractExpectedParams() {
2349
+ if (arguments.length == 1) {
2350
+ return;
2351
+ }
2352
+
2353
+ if (arguments.length == 2) {
2354
+ var expected = arguments[1];
2355
+
2356
+ if (expected instanceof RegExp) {
2357
+ regexp = expected;
2358
+ } else if (typeof expected == "string") {
2359
+ message = expected;
2360
+ } else if (checkForAnErrorType(expected)) {
2361
+ errorType = expected;
2362
+ }
2363
+
2364
+ if (!(errorType || message || regexp)) {
2365
+ throw new Error("Expected is not an Error, string, or RegExp.");
2366
+ }
2367
+ } else {
2368
+ if (checkForAnErrorType(arguments[1])) {
2369
+ errorType = arguments[1];
2370
+ } else {
2371
+ throw new Error("Expected error type is not an Error.");
2372
+ }
2373
+
2374
+ if (arguments[2] instanceof RegExp) {
2375
+ regexp = arguments[2];
2376
+ } else if (typeof arguments[2] == "string") {
2377
+ message = arguments[2];
2378
+ } else {
2379
+ throw new Error("Expected error message is not a string or RegExp.");
2380
+ }
2381
+ }
2382
+ }
2383
+
2384
+ function checkForAnErrorType(type) {
2385
+ if (typeof type !== "function") {
2386
+ return false;
2387
+ }
2388
+
2389
+ var Surrogate = function() {};
2390
+ Surrogate.prototype = type.prototype;
2391
+ return (new Surrogate()) instanceof Error;
2392
+ }
2393
+ }
2394
+ };
2395
+ }
2396
+
2397
+ return toThrowError;
2398
+ };
2399
+
2400
+ getJasmineRequireObj().version = function() {
2401
+ return "2.0.0";
2402
+ };
2403
+