ende 0.4.20 → 0.4.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/build/build.css +111 -0
  4. data/component.json +1 -0
  5. data/lib/assets/javascripts/aura/extensions/models.js.coffee.erb +4 -13
  6. data/lib/assets/javascripts/aura/extensions/platform.js.coffee +2 -8
  7. data/lib/assets/javascripts/aura/extensions/rivets.js.coffee +21 -10
  8. data/lib/assets/javascripts/aura/extensions/states.js.coffee +25 -27
  9. data/lib/assets/javascripts/aura/extensions/widget/eventable.js.coffee +28 -23
  10. data/lib/assets/javascripts/aura/extensions/widget/lifecycleable.js.coffee +21 -34
  11. data/lib/assets/javascripts/aura/extensions/widget/napable.js.coffee +17 -13
  12. data/lib/assets/javascripts/config/load_components.js.coffee +5 -7
  13. data/lib/assets/javascripts/widgets/dialog/main.js.coffee +1 -2
  14. data/lib/assets/javascripts/widgets/list/presenter.js.coffee +5 -4
  15. data/lib/assets/javascripts/widgets/support/adapters/olark.js +1 -1
  16. data/lib/assets/javascripts/widgets/tray/main.js.coffee +16 -22
  17. data/lib/assets/javascripts/widgets/viewer/main.js.coffee +39 -102
  18. data/lib/assets/javascripts/widgets/viewer/plugins/scopable.js.coffee +7 -1
  19. data/lib/ende/version.rb +1 -1
  20. data/vendor/assets/components/ende_build.js +5732 -1047
  21. data/vendor/components/indefinido-indemma/build/development.js +2 -2
  22. data/vendor/components/indefinido-indemma/build/release.js +9 -4
  23. data/vendor/components/indefinido-indemma/build/test.js +115 -21916
  24. data/vendor/components/indefinido-indemma/component.json +0 -1
  25. data/vendor/components/indefinido-indemma/lib/record/restfulable.js +7 -2
  26. data/vendor/components/indefinido-indemma/lib/record/validatable.js +2 -2
  27. data/vendor/components/indefinido-indemma/src/lib/record/persistable.coffee +2 -0
  28. data/vendor/components/indefinido-indemma/src/lib/record/resource.coffee +3 -2
  29. data/vendor/components/indefinido-indemma/src/lib/record/restfulable.coffee +16 -4
  30. data/vendor/components/indefinido-indemma/src/lib/record/validatable.coffee +3 -3
  31. data/vendor/components/indefinido-observable/.gitignore +15 -0
  32. data/vendor/components/indefinido-observable/.ruby-gemset +1 -0
  33. data/vendor/components/indefinido-observable/.ruby-version +1 -0
  34. data/vendor/components/indefinido-observable/Gemfile +13 -0
  35. data/vendor/components/indefinido-observable/Guardfile +39 -0
  36. data/vendor/components/indefinido-observable/History.md +0 -0
  37. data/vendor/components/indefinido-observable/Readme.md +116 -0
  38. data/vendor/components/indefinido-observable/build/build.js +14798 -0
  39. data/vendor/components/indefinido-observable/build/development.js +339 -0
  40. data/vendor/components/indefinido-observable/build/release.js +14937 -0
  41. data/vendor/components/indefinido-observable/build/test.js +339 -0
  42. data/vendor/components/indefinido-observable/component.json +7 -3
  43. data/vendor/components/indefinido-observable/components/chaijs-chai/component.json +46 -0
  44. data/vendor/components/indefinido-observable/components/chaijs-chai/index.js +1 -0
  45. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/assertion.js +132 -0
  46. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/core/assertions.js +1270 -0
  47. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/error.js +60 -0
  48. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/assert.js +1060 -0
  49. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/expect.js +12 -0
  50. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/interface/should.js +76 -0
  51. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addChainableMethod.js +94 -0
  52. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addMethod.js +37 -0
  53. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/addProperty.js +40 -0
  54. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/eql.js +124 -0
  55. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/flag.js +32 -0
  56. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getActual.js +19 -0
  57. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getEnumerableProperties.js +25 -0
  58. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getMessage.js +49 -0
  59. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getName.js +20 -0
  60. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getPathValue.js +102 -0
  61. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/getProperties.js +35 -0
  62. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/index.js +108 -0
  63. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/inspect.js +316 -0
  64. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/objDisplay.js +48 -0
  65. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteMethod.js +51 -0
  66. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/overwriteProperty.js +54 -0
  67. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/test.js +26 -0
  68. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/transferFlags.js +44 -0
  69. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai/utils/type.js +45 -0
  70. data/vendor/components/indefinido-observable/components/chaijs-chai/lib/chai.js +79 -0
  71. data/vendor/components/indefinido-observable/components/cjohansen-sinon/sinon.js +4290 -0
  72. data/vendor/components/indefinido-observable/components/component-jquery/component.json +14 -0
  73. data/vendor/components/indefinido-observable/components/component-jquery/index.js +9601 -0
  74. data/vendor/components/indefinido-observable/components/kapit-observe-shim/component.json +11 -0
  75. data/vendor/components/indefinido-observable/components/kapit-observe-utils/component.json +13 -0
  76. data/vendor/components/indefinido-observable/karma.conf.js +92 -0
  77. data/vendor/components/indefinido-observable/lib/observable.js +9 -19
  78. data/vendor/components/indefinido-observable/spec/legacy/observable_spec.js +126 -0
  79. data/vendor/components/indefinido-observable/spec/observable_spec.js +92 -0
  80. data/vendor/components/indefinido-observable/spec/spec_helper.js +8 -0
  81. data/vendor/components/indefinido-observable/spec/vendor/accessors_spec.js +63 -0
  82. data/vendor/components/indefinido-observable/src/lib/adapters/rivets.js.coffee +15 -0
  83. data/vendor/components/indefinido-observable/src/spec/legacy/observable_spec.coffee +132 -0
  84. data/vendor/components/indefinido-observable/src/spec/observable_spec.coffee +85 -0
  85. data/vendor/components/indefinido-observable/src/spec/spec_helper.coffee +5 -0
  86. data/vendor/components/indefinido-observable/src/spec/vendor/accessors_spec.coffee +59 -0
  87. data/vendor/components/indefinido-observable/vendor/spec/boot.js +104 -0
  88. data/vendor/components/indefinido-observable/vendor/spec/jasmine.js +2054 -0
  89. metadata +60 -8
  90. data/lib/assets/javascripts/aura/extensions/domain.js.coffee +0 -55
  91. data/lib/assets/javascripts/aura/extensions/stamps.js.coffee +0 -35
  92. data/lib/assets/javascripts/aura/extensions/widget/composable.js.coffee +0 -135
  93. data/lib/assets/javascripts/aura/extensions/widget/flowable.js.coffee +0 -65
  94. data/lib/assets/javascripts/widgets/attachable/main.js.coffee +0 -77
  95. /data/{lib/assets/javascripts/aura/extensions/stamps → vendor/assets/javascripts/stampit}/stampit.js +0 -0
@@ -0,0 +1,2054 @@
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
+
24
+ /**
25
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
26
+ *
27
+ * @namespace
28
+ */
29
+ var jasmine = {};
30
+
31
+ // TODO: do we need this now that we have boot.js?
32
+ if (typeof window == "undefined" && typeof exports == "object") {
33
+ exports.jasmine = jasmine;
34
+ }
35
+
36
+ /**
37
+ * @private
38
+ */
39
+ jasmine.unimplementedMethod_ = function() {
40
+ throw new Error("unimplemented method");
41
+ };
42
+
43
+ /**
44
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
45
+ *
46
+ */
47
+ jasmine.DEFAULT_UPDATE_INTERVAL = 250;
48
+
49
+ /**
50
+ * Maximum levels of nesting that will be included when an object is pretty-printed
51
+ */
52
+ jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
53
+
54
+ /**
55
+ * Default timeout interval in milliseconds for waitsFor() blocks.
56
+ */
57
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
58
+
59
+ jasmine.getGlobal = function() {
60
+ function getGlobal() {
61
+ return this;
62
+ }
63
+
64
+ return getGlobal();
65
+ };
66
+
67
+ /**
68
+ * Getter for the Jasmine environment. Ensures one gets created
69
+ */
70
+ jasmine.getEnv = function(options) {
71
+ var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(options);
72
+ //jasmine. singletons in here (setTimeout blah blah).
73
+ return env;
74
+ };
75
+
76
+ /**
77
+ * @ignore
78
+ * @private
79
+ * @param value
80
+ * @returns {Boolean}
81
+ */
82
+ jasmine.isArray_ = function(value) {
83
+ return jasmine.isA_("Array", value);
84
+ };
85
+
86
+ /**
87
+ * @ignore
88
+ * @private
89
+ * @param value
90
+ * @returns {Boolean}
91
+ */
92
+ jasmine.isString_ = function(value) {
93
+ return jasmine.isA_("String", value);
94
+ };
95
+
96
+ /**
97
+ * @ignore
98
+ * @private
99
+ * @param value
100
+ * @returns {Boolean}
101
+ */
102
+ jasmine.isNumber_ = function(value) {
103
+ return jasmine.isA_("Number", value);
104
+ };
105
+
106
+ /**
107
+ * @ignore
108
+ * @private
109
+ * @param {String} typeName
110
+ * @param value
111
+ * @returns {Boolean}
112
+ */
113
+ jasmine.isA_ = function(typeName, value) {
114
+ return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
115
+ };
116
+
117
+ /**
118
+ * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
119
+ *
120
+ * @param value {Object} an object to be outputted
121
+ * @returns {String}
122
+ */
123
+ jasmine.pp = function(value) {
124
+ var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
125
+ stringPrettyPrinter.format(value);
126
+ return stringPrettyPrinter.string;
127
+ };
128
+
129
+ /**
130
+ * Returns true if the object is a DOM Node.
131
+ *
132
+ * @param {Object} obj object to check
133
+ * @returns {Boolean}
134
+ */
135
+ jasmine.isDomNode = function(obj) {
136
+ return obj.nodeType > 0;
137
+ };
138
+
139
+ /**
140
+ * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
141
+ *
142
+ * @example
143
+ * // don't care about which function is passed in, as long as it's a function
144
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
145
+ *
146
+ * @param {Class} clazz
147
+ * @returns matchable object of the type clazz
148
+ */
149
+ jasmine.any = function(clazz) {
150
+ return new jasmine.Matchers.Any(clazz);
151
+ };
152
+
153
+ /**
154
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
155
+ * attributes on the object.
156
+ *
157
+ * @example
158
+ * // don't care about any other attributes than foo.
159
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
160
+ *
161
+ * @param sample {Object} sample
162
+ * @returns matchable object for the sample
163
+ */
164
+ jasmine.objectContaining = function (sample) {
165
+ return new jasmine.Matchers.ObjectContaining(sample);
166
+ };
167
+
168
+ /**
169
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
170
+ *
171
+ * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
172
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
173
+ *
174
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
175
+ *
176
+ * Spies are torn down at the end of every spec.
177
+ *
178
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
179
+ *
180
+ * @example
181
+ * // a stub
182
+ * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
183
+ *
184
+ * // spy example
185
+ * var foo = {
186
+ * not: function(bool) { return !bool; }
187
+ * }
188
+ *
189
+ * // actual foo.not will not be called, execution stops
190
+ * spyOn(foo, 'not');
191
+
192
+ // foo.not spied upon, execution will continue to implementation
193
+ * spyOn(foo, 'not').andCallThrough();
194
+ *
195
+ * // fake example
196
+ * var foo = {
197
+ * not: function(bool) { return !bool; }
198
+ * }
199
+ *
200
+ * // foo.not(val) will return val
201
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
202
+ *
203
+ * // mock example
204
+ * foo.not(7 == 7);
205
+ * expect(foo.not).toHaveBeenCalled();
206
+ * expect(foo.not).toHaveBeenCalledWith(true);
207
+ *
208
+ * @constructor
209
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
210
+ * @param {String} name
211
+ */
212
+ jasmine.Spy = function(name) {
213
+ /**
214
+ * The name of the spy, if provided.
215
+ */
216
+ this.identity = name || 'unknown';
217
+ /**
218
+ * Is this Object a spy?
219
+ */
220
+ this.isSpy = true;
221
+ /**
222
+ * The actual function this spy stubs.
223
+ */
224
+ this.plan = function() {
225
+ };
226
+ /**
227
+ * Tracking of the most recent call to the spy.
228
+ * @example
229
+ * var mySpy = jasmine.createSpy('foo');
230
+ * mySpy(1, 2);
231
+ * mySpy.mostRecentCall.args = [1, 2];
232
+ */
233
+ this.mostRecentCall = {};
234
+
235
+ /**
236
+ * Holds arguments for each call to the spy, indexed by call count
237
+ * @example
238
+ * var mySpy = jasmine.createSpy('foo');
239
+ * mySpy(1, 2);
240
+ * mySpy(7, 8);
241
+ * mySpy.mostRecentCall.args = [7, 8];
242
+ * mySpy.argsForCall[0] = [1, 2];
243
+ * mySpy.argsForCall[1] = [7, 8];
244
+ */
245
+ this.argsForCall = [];
246
+ this.calls = [];
247
+ };
248
+
249
+ /**
250
+ * Tells a spy to call through to the actual implemenatation.
251
+ *
252
+ * @example
253
+ * var foo = {
254
+ * bar: function() { // do some stuff }
255
+ * }
256
+ *
257
+ * // defining a spy on an existing property: foo.bar
258
+ * spyOn(foo, 'bar').andCallThrough();
259
+ */
260
+ jasmine.Spy.prototype.andCallThrough = function() {
261
+ this.plan = this.originalValue;
262
+ return this;
263
+ };
264
+
265
+ /**
266
+ * For setting the return value of a spy.
267
+ *
268
+ * @example
269
+ * // defining a spy from scratch: foo() returns 'baz'
270
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
271
+ *
272
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
273
+ * spyOn(foo, 'bar').andReturn('baz');
274
+ *
275
+ * @param {Object} value
276
+ */
277
+ jasmine.Spy.prototype.andReturn = function(value) {
278
+ this.plan = function() {
279
+ return value;
280
+ };
281
+ return this;
282
+ };
283
+
284
+ /**
285
+ * For throwing an exception when a spy is called.
286
+ *
287
+ * @example
288
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
289
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
290
+ *
291
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
292
+ * spyOn(foo, 'bar').andThrow('baz');
293
+ *
294
+ * @param {String} exceptionMsg
295
+ */
296
+ jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
297
+ this.plan = function() {
298
+ throw exceptionMsg;
299
+ };
300
+ return this;
301
+ };
302
+
303
+ /**
304
+ * Calls an alternate implementation when a spy is called.
305
+ *
306
+ * @example
307
+ * var baz = function() {
308
+ * // do some stuff, return something
309
+ * }
310
+ * // defining a spy from scratch: foo() calls the function baz
311
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
312
+ *
313
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
314
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
315
+ *
316
+ * @param {Function} fakeFunc
317
+ */
318
+ jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
319
+ this.plan = fakeFunc;
320
+ return this;
321
+ };
322
+
323
+ /**
324
+ * Resets all of a spy's the tracking variables so that it can be used again.
325
+ *
326
+ * @example
327
+ * spyOn(foo, 'bar');
328
+ *
329
+ * foo.bar();
330
+ *
331
+ * expect(foo.bar.callCount).toEqual(1);
332
+ *
333
+ * foo.bar.reset();
334
+ *
335
+ * expect(foo.bar.callCount).toEqual(0);
336
+ */
337
+ jasmine.Spy.prototype.reset = function() {
338
+ this.wasCalled = false;
339
+ this.callCount = 0;
340
+ this.argsForCall = [];
341
+ this.calls = [];
342
+ this.mostRecentCall = {};
343
+ };
344
+
345
+ jasmine.createSpy = function(name) {
346
+
347
+ var spyObj = function() {
348
+ spyObj.wasCalled = true;
349
+ spyObj.callCount++;
350
+ var args = jasmine.util.argsToArray(arguments);
351
+ spyObj.mostRecentCall.object = this;
352
+ spyObj.mostRecentCall.args = args;
353
+ spyObj.argsForCall.push(args);
354
+ spyObj.calls.push({object: this, args: args});
355
+ return spyObj.plan.apply(this, arguments);
356
+ };
357
+
358
+ var spy = new jasmine.Spy(name);
359
+
360
+ for (var prop in spy) {
361
+ spyObj[prop] = spy[prop];
362
+ }
363
+
364
+ spyObj.reset();
365
+
366
+ return spyObj;
367
+ };
368
+
369
+ /**
370
+ * Determines whether an object is a spy.
371
+ *
372
+ * @param {jasmine.Spy|Object} putativeSpy
373
+ * @returns {Boolean}
374
+ */
375
+ jasmine.isSpy = function(putativeSpy) {
376
+ return putativeSpy && putativeSpy.isSpy;
377
+ };
378
+
379
+ /**
380
+ * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
381
+ * large in one call.
382
+ *
383
+ * @param {String} baseName name of spy class
384
+ * @param {Array} methodNames array of names of methods to make spies
385
+ */
386
+ jasmine.createSpyObj = function(baseName, methodNames) {
387
+ if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
388
+ throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
389
+ }
390
+ var obj = {};
391
+ for (var i = 0; i < methodNames.length; i++) {
392
+ obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
393
+ }
394
+ return obj;
395
+ };
396
+
397
+ jasmine.util = {};
398
+
399
+ jasmine.util.inherit = function(childClass, parentClass) {
400
+ var subclass = function() {
401
+ };
402
+ subclass.prototype = parentClass.prototype;
403
+ childClass.prototype = new subclass();
404
+ };
405
+
406
+ jasmine.util.formatException = function(e) {
407
+ var lineNumber;
408
+ if (e.line) {
409
+ lineNumber = e.line;
410
+ }
411
+ else if (e.lineNumber) {
412
+ lineNumber = e.lineNumber;
413
+ }
414
+
415
+ var file;
416
+
417
+ if (e.sourceURL) {
418
+ file = e.sourceURL;
419
+ }
420
+ else if (e.fileName) {
421
+ file = e.fileName;
422
+ }
423
+
424
+ var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
425
+
426
+ if (file && lineNumber) {
427
+ message += ' in ' + file + ' (line ' + lineNumber + ')';
428
+ }
429
+
430
+ return message;
431
+ };
432
+
433
+ jasmine.util.htmlEscape = function(str) {
434
+ if (!str) return str;
435
+ return str.replace(/&/g, '&amp;')
436
+ .replace(/</g, '&lt;')
437
+ .replace(/>/g, '&gt;');
438
+ };
439
+
440
+ jasmine.util.argsToArray = function(args) {
441
+ var arrayOfArgs = [];
442
+ for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
443
+ return arrayOfArgs;
444
+ };
445
+
446
+ jasmine.util.isUndefined = function(obj) {
447
+ return obj === void 0;
448
+ };
449
+
450
+ jasmine.Spec = function(attrs) {
451
+ this.encounteredExpectations = false;
452
+ this.expectationFactory = attrs.expectationFactory;
453
+ this.resultCallback = attrs.resultCallback || function() {};
454
+ this.id = attrs.id;
455
+ this.description = attrs.description || '';
456
+ this.fn = attrs.fn;
457
+ this.beforeFns = attrs.beforeFns || function() {};
458
+ this.afterFns = attrs.afterFns || function() {};
459
+ this.catchingExceptions = attrs.catchingExceptions;
460
+ this.onStart = attrs.onStart || function() {};
461
+ this.exceptionFormatter = attrs.exceptionFormatter || function() {};
462
+ this.getSpecName = attrs.getSpecName || function() { return ''; };
463
+ this.expectationResultFactory = attrs.expectationResultFactory || function() { };
464
+ this.queueRunner = attrs.queueRunner || function() {};
465
+ this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
466
+
467
+ if (!this.fn) {
468
+ this.pend();
469
+ }
470
+
471
+ this.result = {
472
+ id: this.id,
473
+ description: this.description,
474
+ fullName: this.getFullName(),
475
+ status: this.status(),
476
+ failedExpectations: []
477
+ };
478
+ };
479
+
480
+ jasmine.Spec.prototype.addExpectationResult = function(passed, data) {
481
+ this.encounteredExpectations = true;
482
+ if (passed) {
483
+ return;
484
+ }
485
+ this.result.failedExpectations.push(this.expectationResultFactory(data));
486
+ };
487
+
488
+ jasmine.Spec.prototype.expect = function(actual) {
489
+ return this.expectationFactory(actual, this);
490
+ };
491
+
492
+ jasmine.Spec.prototype.execute = function(onComplete) {
493
+ var self = this;
494
+
495
+ this.onStart(this);
496
+
497
+ if (this.markedPending || this.disabled) {
498
+ complete();
499
+ return;
500
+ }
501
+
502
+ var befores = this.beforeFns() || [],
503
+ afters = this.afterFns() || [];
504
+ var allFns = befores.concat(this.fn).concat(afters);
505
+
506
+ this.queueRunner({
507
+ fns: allFns,
508
+ onException: function(e) {
509
+ if (jasmine.Spec.isPendingSpecException(e)) {
510
+ self.pend();
511
+ return;
512
+ }
513
+
514
+ self.addExpectationResult(false, {
515
+ matcherName: "",
516
+ passed: false,
517
+ expected: "",
518
+ actual: "",
519
+ error: e
520
+ });
521
+ },
522
+ onComplete: complete
523
+ });
524
+
525
+ function complete() {
526
+ self.result.status = self.status();
527
+ self.resultCallback(self.result);
528
+
529
+ if (onComplete) {
530
+ onComplete();
531
+ }
532
+ }
533
+ };
534
+
535
+ jasmine.Spec.prototype.disable = function() {
536
+ this.disabled = true;
537
+ };
538
+
539
+ jasmine.Spec.prototype.pend = function() {
540
+ this.markedPending = true;
541
+ };
542
+
543
+ jasmine.Spec.prototype.status = function() {
544
+ if (this.disabled) {
545
+ return 'disabled';
546
+ }
547
+
548
+ if (this.markedPending || !this.encounteredExpectations) {
549
+ return 'pending';
550
+ }
551
+
552
+ if (this.result.failedExpectations.length > 0) {
553
+ return 'failed';
554
+ } else {
555
+ return 'passed';
556
+ }
557
+ };
558
+
559
+ jasmine.Spec.prototype.getFullName = function() {
560
+ return this.getSpecName(this);
561
+ };
562
+
563
+ jasmine.Spec.pendingSpecExceptionMessage = "=> marked Pending";
564
+
565
+ jasmine.Spec.isPendingSpecException = function(e) {
566
+ return e.toString().indexOf(jasmine.Spec.pendingSpecExceptionMessage) !== -1;
567
+ };
568
+ (function() {
569
+ jasmine.Env = function(options) {
570
+ options = options || {};
571
+ var self = this;
572
+ var global = options.global || jasmine.getGlobal();
573
+
574
+ var catchExceptions = true;
575
+
576
+ this.clock = new jasmine.Clock(global, new jasmine.DelayedFunctionScheduler());
577
+
578
+ this.jasmine = jasmine;
579
+ this.spies_ = [];
580
+ this.currentSpec = null;
581
+
582
+ this.reporter = new jasmine.ReportDispatcher([
583
+ "jasmineStarted",
584
+ "jasmineDone",
585
+ "suiteStarted",
586
+ "suiteDone",
587
+ "specStarted",
588
+ "specDone"
589
+ ]);
590
+
591
+ this.lastUpdate = 0;
592
+ this.specFilter = function() {
593
+ return true;
594
+ };
595
+
596
+ this.nextSpecId_ = 0;
597
+ this.nextSuiteId_ = 0;
598
+ this.equalityTesters_ = [];
599
+
600
+ // wrap matchers
601
+ this.matchersClass = function() {
602
+ jasmine.Matchers.apply(this, arguments);
603
+ };
604
+ jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
605
+
606
+ jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
607
+
608
+ var expectationFactory = function(actual, spec) {
609
+ var expect = new (self.matchersClass)(self, actual, spec);
610
+ expect.not = new (self.matchersClass)(self, actual, spec, true);
611
+ return expect;
612
+ };
613
+
614
+ var specStarted = function(spec) {
615
+ self.currentSpec = spec;
616
+ self.reporter.specStarted(spec.result);
617
+ };
618
+
619
+ var beforeFns = function(currentSuite) {
620
+ return function() {
621
+ var befores = [];
622
+ for (var suite = currentSuite; suite; suite = suite.parentSuite) {
623
+ befores = befores.concat(suite.beforeFns);
624
+ }
625
+ return befores.reverse();
626
+ };
627
+ };
628
+
629
+ var afterFns = function(currentSuite) {
630
+ return function() {
631
+ var afters = [];
632
+ for (var suite = currentSuite; suite; suite = suite.parentSuite) {
633
+ afters = afters.concat(suite.afterFns);
634
+ }
635
+ return afters;
636
+ };
637
+ };
638
+
639
+ var specConstructor = jasmine.Spec;
640
+
641
+ var getSpecName = function(spec, currentSuite) {
642
+ return currentSuite.getFullName() + ' ' + spec.description + '.';
643
+ };
644
+
645
+ // TODO: we may just be able to pass in the fn instead of wrapping here
646
+ var buildExpectationResult = jasmine.buildExpectationResult,
647
+ exceptionFormatter = new jasmine.ExceptionFormatter(),
648
+ expectationResultFactory = function(attrs) {
649
+ attrs.messageFormatter = exceptionFormatter.message;
650
+ attrs.stackFormatter = exceptionFormatter.stack;
651
+
652
+ return buildExpectationResult(attrs);
653
+ };
654
+
655
+ // TODO: fix this naming, and here's where the value comes in
656
+ this.catchExceptions = function(value) {
657
+ catchExceptions = !!value;
658
+ return catchExceptions;
659
+ };
660
+
661
+ this.catchingExceptions = function() {
662
+ return catchExceptions;
663
+ };
664
+
665
+ this.catchException = function(e){
666
+ return jasmine.Spec.isPendingSpecException(e) || catchExceptions;
667
+ };
668
+
669
+ var maximumSpecCallbackDepth = 100;
670
+ var currentSpecCallbackDepth = 0;
671
+
672
+ function encourageGarbageCollection(fn) {
673
+ currentSpecCallbackDepth++;
674
+ if (currentSpecCallbackDepth > maximumSpecCallbackDepth) {
675
+ currentSpecCallbackDepth = 0;
676
+ global.setTimeout(fn, 0);
677
+ } else {
678
+ fn();
679
+ }
680
+ }
681
+
682
+ var queueRunnerFactory = function(options) {
683
+ options.catchException = self.catchException;
684
+ options.encourageGC = options.encourageGarbageCollection || encourageGarbageCollection;
685
+
686
+ new jasmine.QueueRunner(options).run(options.fns, 0);
687
+ };
688
+
689
+ var totalSpecsDefined = 0;
690
+ this.specFactory = function(description, fn, suite) {
691
+ totalSpecsDefined++;
692
+
693
+ var spec = new specConstructor({
694
+ id: self.nextSpecId(),
695
+ beforeFns: beforeFns(suite),
696
+ afterFns: afterFns(suite),
697
+ expectationFactory: expectationFactory,
698
+ exceptionFormatter: exceptionFormatter,
699
+ resultCallback: specResultCallback,
700
+ getSpecName: function(spec) {
701
+ return getSpecName(spec, suite);
702
+ },
703
+ onStart: specStarted,
704
+ description: description,
705
+ expectationResultFactory: expectationResultFactory,
706
+ queueRunner: queueRunnerFactory,
707
+ fn: fn
708
+ });
709
+
710
+ if (!self.specFilter(spec)) {
711
+ spec.disable();
712
+ }
713
+
714
+ return spec;
715
+
716
+ function specResultCallback(result) {
717
+ self.removeAllSpies();
718
+ self.clock.uninstall();
719
+ self.currentSpec = null;
720
+ self.reporter.specDone(result);
721
+ }
722
+ };
723
+
724
+ var suiteStarted = function(suite) {
725
+ self.reporter.suiteStarted(suite.result);
726
+ };
727
+
728
+ var suiteConstructor = jasmine.Suite;
729
+
730
+ this.topSuite = new jasmine.Suite({
731
+ env: this,
732
+ id: this.nextSuiteId(),
733
+ description: 'Jasmine__TopLevel__Suite',
734
+ queueRunner: queueRunnerFactory,
735
+ completeCallback: function() {}, // TODO - hook this up
736
+ resultCallback: function() {} // TODO - hook this up
737
+ });
738
+ this.currentSuite = this.topSuite;
739
+
740
+ this.suiteFactory = function(description) {
741
+ return new suiteConstructor({
742
+ env: self,
743
+ id: self.nextSuiteId(),
744
+ description: description,
745
+ parentSuite: self.currentSuite,
746
+ queueRunner: queueRunnerFactory,
747
+ onStart: suiteStarted,
748
+ resultCallback: function(attrs) {
749
+ self.reporter.suiteDone(attrs);
750
+ }
751
+ });
752
+ };
753
+
754
+ this.execute = function() {
755
+ this.reporter.jasmineStarted({
756
+ totalSpecsDefined: totalSpecsDefined
757
+ });
758
+ this.topSuite.execute(this.reporter.jasmineDone);
759
+ };
760
+ };
761
+
762
+ //TODO: shim Spec addMatchers behavior into Env. Should be rewritten to remove globals, etc.
763
+ jasmine.Env.prototype.addMatchers = function(matchersPrototype) {
764
+ var parent = this.matchersClass;
765
+ var newMatchersClass = function() {
766
+ parent.apply(this, arguments);
767
+ };
768
+ jasmine.util.inherit(newMatchersClass, parent);
769
+ jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
770
+ this.matchersClass = newMatchersClass;
771
+ };
772
+
773
+ jasmine.Env.prototype.version = function() {
774
+ return jasmine.version;
775
+ };
776
+
777
+ jasmine.Env.prototype.expect = function(actual) {
778
+ return this.currentSpec.expect(actual);
779
+ };
780
+
781
+ jasmine.Env.prototype.spyOn = function(obj, methodName) {
782
+ if (jasmine.util.isUndefined(obj)) {
783
+ throw "spyOn could not find an object to spy upon for " + methodName + "()";
784
+ }
785
+
786
+ if (jasmine.util.isUndefined(obj[methodName])) {
787
+ throw methodName + '() method does not exist';
788
+ }
789
+
790
+ if (obj[methodName] && obj[methodName].isSpy) {
791
+ //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
792
+ throw new Error(methodName + ' has already been spied upon');
793
+ }
794
+
795
+ var spyObj = jasmine.createSpy(methodName);
796
+
797
+ this.spies_.push(spyObj);
798
+ spyObj.baseObj = obj;
799
+ spyObj.methodName = methodName;
800
+ spyObj.originalValue = obj[methodName];
801
+
802
+ obj[methodName] = spyObj;
803
+
804
+ return spyObj;
805
+ };
806
+
807
+ // TODO: move this to closure
808
+ jasmine.Env.prototype.removeAllSpies = function() {
809
+ for (var i = 0; i < this.spies_.length; i++) {
810
+ var spy = this.spies_[i];
811
+ spy.baseObj[spy.methodName] = spy.originalValue;
812
+ }
813
+ this.spies_ = [];
814
+ };
815
+
816
+ // TODO: move this to closure
817
+ jasmine.Env.prototype.versionString = function() {
818
+ console.log("DEPRECATED == use jasmine.version");
819
+ return jasmine.version;
820
+ };
821
+
822
+ // TODO: move this to closure
823
+ jasmine.Env.prototype.nextSpecId = function() {
824
+ return this.nextSpecId_++;
825
+ };
826
+
827
+ // TODO: move this to closure
828
+ jasmine.Env.prototype.nextSuiteId = function() {
829
+ return this.nextSuiteId_++;
830
+ };
831
+
832
+ // TODO: move this to closure
833
+ jasmine.Env.prototype.addReporter = function(reporter) {
834
+ this.reporter.addReporter(reporter);
835
+ };
836
+
837
+ // TODO: move this to closure
838
+ jasmine.Env.prototype.describe = function(description, specDefinitions) {
839
+ var suite = this.suiteFactory(description, specDefinitions);
840
+
841
+ var parentSuite = this.currentSuite;
842
+ parentSuite.addSuite(suite);
843
+ this.currentSuite = suite;
844
+
845
+ var declarationError = null;
846
+ try {
847
+ specDefinitions.call(suite);
848
+ } catch (e) {
849
+ declarationError = e;
850
+ }
851
+
852
+ if (declarationError) {
853
+ this.it("encountered a declaration exception", function() {
854
+ throw declarationError;
855
+ });
856
+ }
857
+
858
+ this.currentSuite = parentSuite;
859
+
860
+ return suite;
861
+ };
862
+
863
+ // TODO: move this to closure
864
+ jasmine.Env.prototype.xdescribe = function(description, specDefinitions) {
865
+ var suite = this.describe(description, specDefinitions);
866
+ suite.disable();
867
+ return suite;
868
+ };
869
+
870
+ // TODO: move this to closure
871
+ jasmine.Env.prototype.it = function(description, fn) {
872
+ var spec = this.specFactory(description, fn, this.currentSuite);
873
+ this.currentSuite.addSpec(spec);
874
+ return spec;
875
+ };
876
+
877
+ // TODO: move this to closure
878
+ jasmine.Env.prototype.xit = function(description, fn) {
879
+ var spec = this.it(description, fn);
880
+ spec.pend();
881
+ return spec;
882
+ };
883
+
884
+ // TODO: move this to closure
885
+ jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
886
+ this.currentSuite.beforeEach(beforeEachFunction);
887
+ };
888
+
889
+ // TODO: move this to closure
890
+ jasmine.Env.prototype.afterEach = function(afterEachFunction) {
891
+ this.currentSuite.afterEach(afterEachFunction);
892
+ };
893
+
894
+ // TODO: move this to closure
895
+ jasmine.Env.prototype.pending = function() {
896
+ throw new Error(jasmine.Spec.pendingSpecExceptionMessage);
897
+ };
898
+
899
+ // TODO: Still needed?
900
+ jasmine.Env.prototype.currentRunner = function() {
901
+ return this.topSuite;
902
+ };
903
+
904
+ jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
905
+ if (a.source != b.source)
906
+ mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
907
+
908
+ if (a.ignoreCase != b.ignoreCase)
909
+ mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
910
+
911
+ if (a.global != b.global)
912
+ mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
913
+
914
+ if (a.multiline != b.multiline)
915
+ mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
916
+
917
+ if (a.sticky != b.sticky)
918
+ mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
919
+
920
+ return (mismatchValues.length === 0);
921
+ };
922
+
923
+ jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
924
+ if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
925
+ return true;
926
+ }
927
+
928
+ a.__Jasmine_been_here_before__ = b;
929
+ b.__Jasmine_been_here_before__ = a;
930
+
931
+ var hasKey = function(obj, keyName) {
932
+ return obj !== null && !jasmine.util.isUndefined(obj[keyName]);
933
+ };
934
+
935
+ for (var property in b) {
936
+ if (!hasKey(a, property) && hasKey(b, property)) {
937
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
938
+ }
939
+ }
940
+ for (property in a) {
941
+ if (!hasKey(b, property) && hasKey(a, property)) {
942
+ mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
943
+ }
944
+ }
945
+ for (property in b) {
946
+ if (property == '__Jasmine_been_here_before__') continue;
947
+ if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
948
+ mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
949
+ }
950
+ }
951
+
952
+ if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
953
+ mismatchValues.push("arrays were not the same length");
954
+ }
955
+
956
+ delete a.__Jasmine_been_here_before__;
957
+ delete b.__Jasmine_been_here_before__;
958
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
959
+ };
960
+
961
+ jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
962
+ mismatchKeys = mismatchKeys || [];
963
+ mismatchValues = mismatchValues || [];
964
+
965
+ for (var i = 0; i < this.equalityTesters_.length; i++) {
966
+ var equalityTester = this.equalityTesters_[i];
967
+ var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
968
+ if (!jasmine.util.isUndefined(result)) {
969
+ return result;
970
+ }
971
+ }
972
+
973
+ if (a === b) return true;
974
+
975
+ if (jasmine.util.isUndefined(a) || a === null || jasmine.util.isUndefined(b) || b === null) {
976
+ return (jasmine.util.isUndefined(a) && jasmine.util.isUndefined(b));
977
+ }
978
+
979
+ if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
980
+ return a === b;
981
+ }
982
+
983
+ if (a instanceof Date && b instanceof Date) {
984
+ return a.getTime() == b.getTime();
985
+ }
986
+
987
+ if (a.jasmineMatches) {
988
+ return a.jasmineMatches(b);
989
+ }
990
+
991
+ if (b.jasmineMatches) {
992
+ return b.jasmineMatches(a);
993
+ }
994
+
995
+ if (a instanceof jasmine.Matchers.ObjectContaining) {
996
+ return a.matches(b);
997
+ }
998
+
999
+ if (b instanceof jasmine.Matchers.ObjectContaining) {
1000
+ return b.matches(a);
1001
+ }
1002
+
1003
+ if (jasmine.isString_(a) && jasmine.isString_(b)) {
1004
+ return (a == b);
1005
+ }
1006
+
1007
+ if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
1008
+ return (a == b);
1009
+ }
1010
+
1011
+ if (a instanceof RegExp && b instanceof RegExp) {
1012
+ return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
1013
+ }
1014
+
1015
+ if (typeof a === "object" && typeof b === "object") {
1016
+ return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
1017
+ }
1018
+
1019
+ //Straight check
1020
+ return (a === b);
1021
+ };
1022
+
1023
+ jasmine.Env.prototype.contains_ = function(haystack, needle) {
1024
+ if (jasmine.isArray_(haystack)) {
1025
+ for (var i = 0; i < haystack.length; i++) {
1026
+ if (this.equals_(haystack[i], needle)) return true;
1027
+ }
1028
+ return false;
1029
+ }
1030
+ return haystack.indexOf(needle) >= 0;
1031
+ };
1032
+
1033
+ jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
1034
+ this.equalityTesters_.push(equalityTester);
1035
+ };
1036
+ }());
1037
+
1038
+ jasmine.JsApiReporter = function(jasmine) {
1039
+ this.jasmine = jasmine || {};
1040
+ this.started = false;
1041
+ this.finished = false;
1042
+
1043
+ var status = 'loaded';
1044
+
1045
+ this.jasmineStarted = function() {
1046
+ this.started = true;
1047
+ status = 'started';
1048
+ };
1049
+
1050
+ this.jasmineDone = function() {
1051
+ this.finished = true;
1052
+ status = 'done';
1053
+ };
1054
+
1055
+ this.status = function() {
1056
+ return status;
1057
+ };
1058
+
1059
+ var suites = {};
1060
+
1061
+ this.suiteStarted = function(result) {
1062
+ storeSuite(result);
1063
+ };
1064
+
1065
+ this.suiteDone = function(result) {
1066
+ storeSuite(result);
1067
+ };
1068
+
1069
+ function storeSuite(result) {
1070
+ suites[result.id] = result;
1071
+ }
1072
+
1073
+ this.suites = function() {
1074
+ return suites;
1075
+ };
1076
+
1077
+ var specs = [];
1078
+ this.specStarted = function(result) { };
1079
+
1080
+ this.specDone = function(result) {
1081
+ specs.push(result);
1082
+ };
1083
+
1084
+ this.specResults = function(index, length) {
1085
+ return specs.slice(index, index + length);
1086
+ };
1087
+
1088
+ this.specs = function() {
1089
+ return specs;
1090
+ };
1091
+
1092
+ };
1093
+ jasmine.Clock = function(global, delayedFunctionScheduler) {
1094
+ var self = this,
1095
+ realTimingFunctions = {
1096
+ setTimeout: global.setTimeout,
1097
+ clearTimeout: global.clearTimeout,
1098
+ setInterval: global.setInterval,
1099
+ clearInterval: global.clearInterval
1100
+ },
1101
+ fakeTimingFunctions = {
1102
+ setTimeout: setTimeout,
1103
+ clearTimeout: clearTimeout,
1104
+ setInterval: setInterval,
1105
+ clearInterval: clearInterval
1106
+ },
1107
+ timer = realTimingFunctions,
1108
+ installed = false;
1109
+
1110
+ self.install = function() {
1111
+ installed = true;
1112
+ timer = fakeTimingFunctions;
1113
+ };
1114
+
1115
+ self.uninstall = function() {
1116
+ delayedFunctionScheduler.reset();
1117
+ installed = false;
1118
+ timer = realTimingFunctions;
1119
+ };
1120
+
1121
+ self.setTimeout = function(fn, delay, params) {
1122
+ if (legacyIE()) {
1123
+ if (arguments.length > 2) {
1124
+ throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
1125
+ }
1126
+ return timer.setTimeout(fn, delay);
1127
+ }
1128
+ return timer.setTimeout.apply(null, arguments);
1129
+ };
1130
+
1131
+ self.setInterval = function(fn, delay, params) {
1132
+ if (legacyIE()) {
1133
+ if (arguments.length > 2) {
1134
+ throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
1135
+ }
1136
+ return timer.setInterval(fn, delay);
1137
+ }
1138
+ return timer.setInterval.apply(null, arguments);
1139
+ };
1140
+
1141
+ self.clearTimeout = function(id) {
1142
+ return timer.clearTimeout(id);
1143
+ };
1144
+
1145
+ self.clearInterval = function(id) {
1146
+ return timer.clearInterval(id);
1147
+ };
1148
+
1149
+ self.tick = function(millis) {
1150
+ if (installed) {
1151
+ delayedFunctionScheduler.tick(millis);
1152
+ } else {
1153
+ throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
1154
+ }
1155
+ };
1156
+
1157
+ return self;
1158
+
1159
+ function legacyIE() {
1160
+ //if these methods are polyfilled, apply will be present
1161
+ //TODO: it may be difficult to load the polyfill before jasmine loads
1162
+ //(env should be new-ed inside of onload)
1163
+ return !(global.setTimeout || global.setInterval).apply;
1164
+ }
1165
+
1166
+ function setTimeout(fn, delay) {
1167
+ return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
1168
+ }
1169
+
1170
+ function clearTimeout(id) {
1171
+ return delayedFunctionScheduler.removeFunctionWithId(id);
1172
+ }
1173
+
1174
+ function setInterval(fn, interval) {
1175
+ return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
1176
+ }
1177
+
1178
+ function clearInterval(id) {
1179
+ return delayedFunctionScheduler.removeFunctionWithId(id);
1180
+ }
1181
+
1182
+ function argSlice(argsObj, n) {
1183
+ return Array.prototype.slice.call(argsObj, 2);
1184
+ }
1185
+ };
1186
+
1187
+ jasmine.DelayedFunctionScheduler = function() {
1188
+ var self = this;
1189
+ var scheduledFunctions = {};
1190
+ var currentTime = 0;
1191
+ var delayedFnCount = 0;
1192
+
1193
+ self.tick = function(millis) {
1194
+ runFunctionsWithinRange(currentTime, currentTime + millis);
1195
+ currentTime = currentTime + millis;
1196
+ };
1197
+
1198
+ self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
1199
+ timeoutKey = timeoutKey || ++delayedFnCount;
1200
+ runAtMillis = runAtMillis || (currentTime + millis);
1201
+ scheduledFunctions[timeoutKey] = {
1202
+ runAtMillis: runAtMillis,
1203
+ funcToCall: funcToCall,
1204
+ recurring: recurring,
1205
+ params: params,
1206
+ timeoutKey: timeoutKey,
1207
+ millis: millis
1208
+ };
1209
+ return timeoutKey;
1210
+ };
1211
+
1212
+ self.removeFunctionWithId = function(timeoutKey) {
1213
+ delete scheduledFunctions[timeoutKey];
1214
+ };
1215
+
1216
+ self.reset = function() {
1217
+ currentTime = 0;
1218
+ scheduledFunctions = {};
1219
+ delayedFnCount = 0;
1220
+ };
1221
+
1222
+ return self;
1223
+
1224
+
1225
+ //finds/dupes functions within range and removes them.
1226
+ function functionsWithinRange(startMillis, endMillis) {
1227
+ var fnsToRun = [];
1228
+ for (var timeoutKey in scheduledFunctions) {
1229
+ var scheduledFunc = scheduledFunctions[timeoutKey];
1230
+ if (scheduledFunc &&
1231
+ scheduledFunc.runAtMillis >= startMillis &&
1232
+ scheduledFunc.runAtMillis <= endMillis) {
1233
+ //remove fn -- we'll reschedule later if it is recurring.
1234
+ self.removeFunctionWithId(timeoutKey);
1235
+ if (!scheduledFunc.recurring) {
1236
+ fnsToRun.push(scheduledFunc); // schedules each function only once
1237
+ } else {
1238
+ fnsToRun.push(buildNthInstanceOf(scheduledFunc, 0));
1239
+ var additionalTimesFnRunsInRange =
1240
+ Math.floor((endMillis - scheduledFunc.runAtMillis) / scheduledFunc.millis);
1241
+ for (var i = 0; i < additionalTimesFnRunsInRange; i++) {
1242
+ fnsToRun.push(buildNthInstanceOf(scheduledFunc, i + 1));
1243
+ }
1244
+ reschedule(buildNthInstanceOf(scheduledFunc, additionalTimesFnRunsInRange));
1245
+ }
1246
+ }
1247
+ }
1248
+
1249
+ return fnsToRun;
1250
+ }
1251
+
1252
+ function buildNthInstanceOf(scheduledFunc, n) {
1253
+ return {
1254
+ runAtMillis: scheduledFunc.runAtMillis + (scheduledFunc.millis * n),
1255
+ funcToCall: scheduledFunc.funcToCall,
1256
+ params: scheduledFunc.params,
1257
+ millis: scheduledFunc.millis,
1258
+ recurring: scheduledFunc.recurring,
1259
+ timeoutKey: scheduledFunc.timeoutKey
1260
+ };
1261
+ }
1262
+
1263
+ function reschedule(scheduledFn) {
1264
+ self.scheduleFunction(scheduledFn.funcToCall,
1265
+ scheduledFn.millis,
1266
+ scheduledFn.params,
1267
+ true,
1268
+ scheduledFn.timeoutKey,
1269
+ scheduledFn.runAtMillis + scheduledFn.millis);
1270
+ }
1271
+
1272
+
1273
+ function runFunctionsWithinRange(startMillis, endMillis) {
1274
+ var funcsToRun = functionsWithinRange(startMillis, endMillis);
1275
+ if (funcsToRun.length === 0) {
1276
+ return;
1277
+ }
1278
+
1279
+ funcsToRun.sort(function(a, b) {
1280
+ return a.runAtMillis - b.runAtMillis;
1281
+ });
1282
+
1283
+ for (var i = 0; i < funcsToRun.length; ++i) {
1284
+ var funcToRun = funcsToRun[i];
1285
+ funcToRun.funcToCall.apply(null, funcToRun.params);
1286
+ }
1287
+ }
1288
+ };
1289
+
1290
+ jasmine.ExceptionFormatter = function() {
1291
+ this.message = function(error) {
1292
+ var message = error.name +
1293
+ ': ' +
1294
+ error.message;
1295
+
1296
+ if (error.fileName || error.sourceURL) {
1297
+ message += " in " + (error.fileName || error.sourceURL);
1298
+ }
1299
+
1300
+ if (error.line || error.lineNumber) {
1301
+ message += " (line " + (error.line || error.lineNumber) + ")";
1302
+ }
1303
+
1304
+ return message;
1305
+ };
1306
+
1307
+ this.stack = function(error) {
1308
+ return error ? error.stack : null;
1309
+ };
1310
+ };
1311
+ //TODO: expectation result may make more sense as a presentation of an expectation.
1312
+ jasmine.buildExpectationResult = function(options) {
1313
+ var messageFormatter = options.messageFormatter || function() {},
1314
+ stackFormatter = options.stackFormatter || function() {};
1315
+
1316
+ return {
1317
+ matcherName: options.matcherName,
1318
+ expected: options.expected,
1319
+ actual: options.actual,
1320
+ message: message(),
1321
+ stack: stack(),
1322
+ passed: options.passed
1323
+ };
1324
+
1325
+ function message() {
1326
+ if (options.passed) {
1327
+ return "Passed.";
1328
+ } else if (options.message) {
1329
+ return options.message;
1330
+ } else if (options.error) {
1331
+ return messageFormatter(options.error);
1332
+ }
1333
+ return "";
1334
+ }
1335
+
1336
+ function stack() {
1337
+ if (options.passed) {
1338
+ return "";
1339
+ }
1340
+
1341
+ var error = options.error;
1342
+ if (!error) {
1343
+ try {
1344
+ throw new Error(message());
1345
+ } catch (e) {
1346
+ error = e;
1347
+ }
1348
+ }
1349
+ return stackFormatter(error);
1350
+ }
1351
+ };
1352
+
1353
+ /**
1354
+ * @constructor
1355
+ * @param {jasmine.Env} env
1356
+ * @param actual
1357
+ * @param {jasmine.Spec} spec
1358
+ */
1359
+ jasmine.Matchers = function(env, actual, spec, opt_isNot) {
1360
+ //TODO: true dependency: equals, contains
1361
+ this.env = env;
1362
+ this.actual = actual;
1363
+ this.spec = spec;
1364
+ this.isNot = opt_isNot || false;
1365
+ };
1366
+
1367
+ // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
1368
+ jasmine.Matchers.pp = function(str) {
1369
+ throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
1370
+ };
1371
+
1372
+
1373
+ jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
1374
+ for (var methodName in prototype) {
1375
+ var orig = prototype[methodName];
1376
+ matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
1377
+ }
1378
+ };
1379
+
1380
+ jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
1381
+ return function() {
1382
+ var matcherArgs = jasmine.util.argsToArray(arguments);
1383
+ var result = matcherFunction.apply(this, arguments);
1384
+
1385
+ if (this.isNot) {
1386
+ result = !result;
1387
+ }
1388
+
1389
+ var message;
1390
+ if (!result) {
1391
+ if (this.message) {
1392
+ message = this.message.apply(this, arguments);
1393
+ if (jasmine.isArray_(message)) {
1394
+ message = message[this.isNot ? 1 : 0];
1395
+ }
1396
+ } else {
1397
+ var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1398
+ message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
1399
+ if (matcherArgs.length > 0) {
1400
+ for (var i = 0; i < matcherArgs.length; i++) {
1401
+ if (i > 0) message += ",";
1402
+ message += " " + jasmine.pp(matcherArgs[i]);
1403
+ }
1404
+ }
1405
+ message += ".";
1406
+ }
1407
+ }
1408
+
1409
+ this.spec.addExpectationResult(result, {
1410
+ matcherName: matcherName,
1411
+ passed: result,
1412
+ expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
1413
+ actual: this.actual,
1414
+ message: message
1415
+ });
1416
+ return void 0;
1417
+ };
1418
+ };
1419
+
1420
+
1421
+ /**
1422
+ * toBe: compares the actual to the expected using ===
1423
+ * @param expected
1424
+ */
1425
+ jasmine.Matchers.prototype.toBe = function(expected) {
1426
+ return this.actual === expected;
1427
+ };
1428
+
1429
+ /**
1430
+ * toNotBe: compares the actual to the expected using !==
1431
+ * @param expected
1432
+ * @deprecated as of 1.0. Use not.toBe() instead.
1433
+ */
1434
+ jasmine.Matchers.prototype.toNotBe = function(expected) {
1435
+ return this.actual !== expected;
1436
+ };
1437
+
1438
+ /**
1439
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
1440
+ *
1441
+ * @param expected
1442
+ */
1443
+ jasmine.Matchers.prototype.toEqual = function(expected) {
1444
+ return this.env.equals_(this.actual, expected);
1445
+ };
1446
+
1447
+ /**
1448
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
1449
+ * @param expected
1450
+ * @deprecated as of 1.0. Use not.toEqual() instead.
1451
+ */
1452
+ jasmine.Matchers.prototype.toNotEqual = function(expected) {
1453
+ return !this.env.equals_(this.actual, expected);
1454
+ };
1455
+
1456
+ /**
1457
+ * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
1458
+ * a pattern or a String.
1459
+ *
1460
+ * @param expected
1461
+ */
1462
+ jasmine.Matchers.prototype.toMatch = function(expected) {
1463
+ return new RegExp(expected).test(this.actual);
1464
+ };
1465
+
1466
+ /**
1467
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
1468
+ * @param expected
1469
+ * @deprecated as of 1.0. Use not.toMatch() instead.
1470
+ */
1471
+ jasmine.Matchers.prototype.toNotMatch = function(expected) {
1472
+ return !(new RegExp(expected).test(this.actual));
1473
+ };
1474
+
1475
+ /**
1476
+ * Matcher that compares the actual to jasmine.undefined.
1477
+ */
1478
+ jasmine.Matchers.prototype.toBeDefined = function() {
1479
+ return !jasmine.util.isUndefined(this.actual);
1480
+ };
1481
+
1482
+ /**
1483
+ * Matcher that compares the actual to jasmine.undefined.
1484
+ */
1485
+ jasmine.Matchers.prototype.toBeUndefined = function() {
1486
+ return jasmine.util.isUndefined(this.actual);
1487
+ };
1488
+
1489
+ /**
1490
+ * Matcher that compares the actual to null.
1491
+ */
1492
+ jasmine.Matchers.prototype.toBeNull = function() {
1493
+ return (this.actual === null);
1494
+ };
1495
+
1496
+ /**
1497
+ * Matcher that compares the actual to NaN.
1498
+ */
1499
+ jasmine.Matchers.prototype.toBeNaN = function() {
1500
+ this.message = function() {
1501
+ return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
1502
+ };
1503
+
1504
+ return (this.actual !== this.actual);
1505
+ };
1506
+
1507
+ /**
1508
+ * Matcher that boolean not-nots the actual.
1509
+ */
1510
+ jasmine.Matchers.prototype.toBeTruthy = function() {
1511
+ return !!this.actual;
1512
+ };
1513
+
1514
+
1515
+ /**
1516
+ * Matcher that boolean nots the actual.
1517
+ */
1518
+ jasmine.Matchers.prototype.toBeFalsy = function() {
1519
+ return !this.actual;
1520
+ };
1521
+
1522
+
1523
+ /**
1524
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
1525
+ */
1526
+ jasmine.Matchers.prototype.toHaveBeenCalled = function() {
1527
+ if (arguments.length > 0) {
1528
+ throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
1529
+ }
1530
+
1531
+ if (!jasmine.isSpy(this.actual)) {
1532
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1533
+ }
1534
+
1535
+ this.message = function() {
1536
+ return [
1537
+ "Expected spy " + this.actual.identity + " to have been called.",
1538
+ "Expected spy " + this.actual.identity + " not to have been called."
1539
+ ];
1540
+ };
1541
+
1542
+ return this.actual.wasCalled;
1543
+ };
1544
+
1545
+ /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
1546
+ jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
1547
+
1548
+ /**
1549
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
1550
+ *
1551
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
1552
+ */
1553
+ jasmine.Matchers.prototype.wasNotCalled = function() {
1554
+ if (arguments.length > 0) {
1555
+ throw new Error('wasNotCalled does not take arguments');
1556
+ }
1557
+
1558
+ if (!jasmine.isSpy(this.actual)) {
1559
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1560
+ }
1561
+
1562
+ this.message = function() {
1563
+ return [
1564
+ "Expected spy " + this.actual.identity + " to not have been called.",
1565
+ "Expected spy " + this.actual.identity + " to have been called."
1566
+ ];
1567
+ };
1568
+
1569
+ return !this.actual.wasCalled;
1570
+ };
1571
+
1572
+ /**
1573
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
1574
+ *
1575
+ * @example
1576
+ *
1577
+ */
1578
+ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
1579
+ var expectedArgs = jasmine.util.argsToArray(arguments);
1580
+ if (!jasmine.isSpy(this.actual)) {
1581
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1582
+ }
1583
+ this.message = function() {
1584
+ var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
1585
+ var positiveMessage = "";
1586
+ if (this.actual.callCount === 0) {
1587
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
1588
+ } else {
1589
+ positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '');
1590
+ }
1591
+ return [positiveMessage, invertedMessage];
1592
+ };
1593
+
1594
+ return this.env.contains_(this.actual.argsForCall, expectedArgs);
1595
+ };
1596
+
1597
+ /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
1598
+ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
1599
+
1600
+ /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
1601
+ jasmine.Matchers.prototype.wasNotCalledWith = function() {
1602
+ var expectedArgs = jasmine.util.argsToArray(arguments);
1603
+ if (!jasmine.isSpy(this.actual)) {
1604
+ throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1605
+ }
1606
+
1607
+ this.message = function() {
1608
+ return [
1609
+ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
1610
+ "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
1611
+ ];
1612
+ };
1613
+
1614
+ return !this.env.contains_(this.actual.argsForCall, expectedArgs);
1615
+ };
1616
+
1617
+ /**
1618
+ * Matcher that checks that the expected item is an element in the actual Array.
1619
+ *
1620
+ * @param {Object} expected
1621
+ */
1622
+ jasmine.Matchers.prototype.toContain = function(expected) {
1623
+ return this.env.contains_(this.actual, expected);
1624
+ };
1625
+
1626
+ /**
1627
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
1628
+ *
1629
+ * @param {Object} expected
1630
+ * @deprecated as of 1.0. Use not.toContain() instead.
1631
+ */
1632
+ jasmine.Matchers.prototype.toNotContain = function(expected) {
1633
+ return !this.env.contains_(this.actual, expected);
1634
+ };
1635
+
1636
+ jasmine.Matchers.prototype.toBeLessThan = function(expected) {
1637
+ return this.actual < expected;
1638
+ };
1639
+
1640
+ jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
1641
+ return this.actual > expected;
1642
+ };
1643
+
1644
+ /**
1645
+ * Matcher that checks that the expected item is equal to the actual item
1646
+ * up to a given level of decimal precision (default 2).
1647
+ *
1648
+ * @param {Number} expected
1649
+ * @param {Number} precision, as number of decimal places
1650
+ */
1651
+ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
1652
+ if (precision !== 0) {
1653
+ precision = precision || 2;
1654
+ }
1655
+ return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
1656
+ };
1657
+
1658
+ /**
1659
+ * Matcher that checks that the expected exception was thrown by the actual.
1660
+ *
1661
+ * @param {String} [expected]
1662
+ */
1663
+ jasmine.Matchers.prototype.toThrow = function(expected) {
1664
+ var result = false;
1665
+ var exception;
1666
+ if (typeof this.actual != 'function') {
1667
+ throw new Error('Actual is not a function');
1668
+ }
1669
+ try {
1670
+ this.actual();
1671
+ } catch (e) {
1672
+ exception = e;
1673
+ }
1674
+
1675
+ if (exception) {
1676
+ result = (jasmine.util.isUndefined(expected) || this.env.equals_(exception.message || exception, expected.message || expected));
1677
+ }
1678
+
1679
+ var not = this.isNot ? "not " : "";
1680
+
1681
+ this.message = function() {
1682
+ if (exception && (jasmine.util.isUndefined(expected) || !this.env.equals_(exception.message || exception, expected.message || expected))) {
1683
+ return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
1684
+ } else {
1685
+ return "Expected function to throw an exception.";
1686
+ }
1687
+ };
1688
+
1689
+ return result;
1690
+ };
1691
+
1692
+ jasmine.Matchers.Any = function(expectedClass) {
1693
+ this.expectedClass = expectedClass;
1694
+ };
1695
+
1696
+ jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
1697
+ if (this.expectedClass == String) {
1698
+ return typeof other == 'string' || other instanceof String;
1699
+ }
1700
+
1701
+ if (this.expectedClass == Number) {
1702
+ return typeof other == 'number' || other instanceof Number;
1703
+ }
1704
+
1705
+ if (this.expectedClass == Function) {
1706
+ return typeof other == 'function' || other instanceof Function;
1707
+ }
1708
+
1709
+ if (this.expectedClass == Object) {
1710
+ return typeof other == 'object';
1711
+ }
1712
+
1713
+ return other instanceof this.expectedClass;
1714
+ };
1715
+
1716
+ jasmine.Matchers.Any.prototype.jasmineToString = function() {
1717
+ return '<jasmine.any(' + this.expectedClass + ')>';
1718
+ };
1719
+
1720
+ jasmine.Matchers.ObjectContaining = function(sample) {
1721
+ this.sample = sample;
1722
+ };
1723
+
1724
+ jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
1725
+ mismatchKeys = mismatchKeys || [];
1726
+ mismatchValues = mismatchValues || [];
1727
+
1728
+ var env = jasmine.getEnv();
1729
+
1730
+ var hasKey = function(obj, keyName) {
1731
+ return obj !== null && !jasmine.util.isUndefined(obj[keyName]);
1732
+ };
1733
+
1734
+ for (var property in this.sample) {
1735
+ if (!hasKey(other, property) && hasKey(this.sample, property)) {
1736
+ mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1737
+ }
1738
+ else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
1739
+ mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
1740
+ }
1741
+ }
1742
+
1743
+ return (mismatchKeys.length === 0 && mismatchValues.length === 0);
1744
+ };
1745
+
1746
+ jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function() {
1747
+ return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
1748
+ };
1749
+
1750
+ /**
1751
+ * Base class for pretty printing for expectation results.
1752
+ */
1753
+ jasmine.PrettyPrinter = function() {
1754
+ this.ppNestLevel_ = 0;
1755
+ };
1756
+
1757
+ /**
1758
+ * Formats a value in a nice, human-readable string.
1759
+ *
1760
+ * @param value
1761
+ */
1762
+ jasmine.PrettyPrinter.prototype.format = function(value) {
1763
+ this.ppNestLevel_++;
1764
+ try {
1765
+ if (jasmine.util.isUndefined(value)) {
1766
+ this.emitScalar('undefined');
1767
+ } else if (value === null) {
1768
+ this.emitScalar('null');
1769
+ } else if (value === jasmine.getGlobal()) {
1770
+ this.emitScalar('<global>');
1771
+ } else if (value.jasmineToString) {
1772
+ this.emitScalar(value.jasmineToString());
1773
+ } else if (typeof value === 'string') {
1774
+ this.emitString(value);
1775
+ } else if (jasmine.isSpy(value)) {
1776
+ this.emitScalar("spy on " + value.identity);
1777
+ } else if (value instanceof RegExp) {
1778
+ this.emitScalar(value.toString());
1779
+ } else if (typeof value === 'function') {
1780
+ this.emitScalar('Function');
1781
+ } else if (typeof value.nodeType === 'number') {
1782
+ this.emitScalar('HTMLNode');
1783
+ } else if (value instanceof Date) {
1784
+ this.emitScalar('Date(' + value + ')');
1785
+ } else if (value.__Jasmine_been_here_before__) {
1786
+ this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
1787
+ } else if (jasmine.isArray_(value) || typeof value == 'object') {
1788
+ value.__Jasmine_been_here_before__ = true;
1789
+ if (jasmine.isArray_(value)) {
1790
+ this.emitArray(value);
1791
+ } else {
1792
+ this.emitObject(value);
1793
+ }
1794
+ delete value.__Jasmine_been_here_before__;
1795
+ } else {
1796
+ this.emitScalar(value.toString());
1797
+ }
1798
+ } finally {
1799
+ this.ppNestLevel_--;
1800
+ }
1801
+ };
1802
+
1803
+ jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1804
+ for (var property in obj) {
1805
+ if (!obj.hasOwnProperty(property)) continue;
1806
+ if (property == '__Jasmine_been_here_before__') continue;
1807
+ fn(property, obj.__lookupGetter__ ? (!jasmine.util.isUndefined(obj.__lookupGetter__(property)) &&
1808
+ obj.__lookupGetter__(property) !== null) : false);
1809
+ }
1810
+ };
1811
+
1812
+ jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
1813
+ jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
1814
+ jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
1815
+ jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
1816
+
1817
+ jasmine.StringPrettyPrinter = function() {
1818
+ jasmine.PrettyPrinter.call(this);
1819
+
1820
+ this.string = '';
1821
+ };
1822
+ jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
1823
+
1824
+ jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
1825
+ this.append(value);
1826
+ };
1827
+
1828
+ jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
1829
+ this.append("'" + value + "'");
1830
+ };
1831
+
1832
+ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
1833
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1834
+ this.append("Array");
1835
+ return;
1836
+ }
1837
+
1838
+ this.append('[ ');
1839
+ for (var i = 0; i < array.length; i++) {
1840
+ if (i > 0) {
1841
+ this.append(', ');
1842
+ }
1843
+ this.format(array[i]);
1844
+ }
1845
+ this.append(' ]');
1846
+ };
1847
+
1848
+ jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
1849
+ if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1850
+ this.append("Object");
1851
+ return;
1852
+ }
1853
+
1854
+ var self = this;
1855
+ this.append('{ ');
1856
+ var first = true;
1857
+
1858
+ this.iterateObject(obj, function(property, isGetter) {
1859
+ if (first) {
1860
+ first = false;
1861
+ } else {
1862
+ self.append(', ');
1863
+ }
1864
+
1865
+ self.append(property);
1866
+ self.append(' : ');
1867
+ if (isGetter) {
1868
+ self.append('<getter>');
1869
+ } else {
1870
+ self.format(obj[property]);
1871
+ }
1872
+ });
1873
+
1874
+ this.append(' }');
1875
+ };
1876
+
1877
+ jasmine.StringPrettyPrinter.prototype.append = function(value) {
1878
+ this.string += value;
1879
+ };
1880
+
1881
+ jasmine.QueueRunner = function(attrs) {
1882
+ this.fns = attrs.fns || [];
1883
+ this.onComplete = attrs.onComplete || function() {};
1884
+ this.encourageGC = attrs.encourageGC || function(fn) {fn();};
1885
+ this.onException = attrs.onException || function() {};
1886
+ this.catchException = attrs.catchException || function() { return true; };
1887
+ };
1888
+
1889
+ jasmine.QueueRunner.prototype.execute = function() {
1890
+ this.run(this.fns, 0);
1891
+ };
1892
+
1893
+ jasmine.QueueRunner.prototype.run = function(fns, index) {
1894
+ if (index >= fns.length) {
1895
+ this.encourageGC(this.onComplete);
1896
+ return;
1897
+ }
1898
+
1899
+ var fn = fns[index];
1900
+ var self = this;
1901
+ if (fn.length > 0) {
1902
+ attempt(function() { fn.call(self, function() { self.run(fns, index + 1); }); });
1903
+ } else {
1904
+ attempt(function() { fn.call(self); });
1905
+ self.run(fns, index + 1);
1906
+ }
1907
+
1908
+ function attempt(fn) {
1909
+ try {
1910
+ fn();
1911
+ } catch (e) {
1912
+ self.onException(e);
1913
+ if (!self.catchException(e)) {
1914
+ //TODO: set a var when we catch an exception and
1915
+ //use a finally block to close the loop in a nice way..
1916
+ throw e;
1917
+ }
1918
+ }
1919
+ }
1920
+ };
1921
+
1922
+ jasmine.ReportDispatcher = function(methods) {
1923
+
1924
+ var dispatchedMethods = methods || [];
1925
+
1926
+ for (var i = 0; i < dispatchedMethods.length; i++) {
1927
+ var method = dispatchedMethods[i];
1928
+ this[method] = function(m) {
1929
+ return function() {
1930
+ dispatch(m, arguments);
1931
+ };
1932
+ }(method);
1933
+ }
1934
+
1935
+ var reporters = [];
1936
+
1937
+ this.addReporter = function(reporter) {
1938
+ reporters.push(reporter);
1939
+ };
1940
+
1941
+ return this;
1942
+
1943
+ function dispatch(method, args) {
1944
+ for (var i = 0; i < reporters.length; i++) {
1945
+ var reporter = reporters[i];
1946
+ if (reporter[method]) {
1947
+ reporter[method].apply(reporter, args);
1948
+ }
1949
+ }
1950
+ }
1951
+ };
1952
+ jasmine.Suite = function(attrs) {
1953
+ this.env = attrs.env;
1954
+ this.id = attrs.id;
1955
+ this.parentSuite = attrs.parentSuite;
1956
+ this.description = attrs.description;
1957
+ this.onStart = attrs.onStart || function() {};
1958
+ this.completeCallback = attrs.completeCallback || function() {};
1959
+ this.resultCallback = attrs.resultCallback || function() {};
1960
+ this.encourageGC = attrs.encourageGC || function(fn) {fn();};
1961
+
1962
+ this.beforeFns = [];
1963
+ this.afterFns = [];
1964
+ this.queueRunner = attrs.queueRunner || function() {};
1965
+ this.disabled = false;
1966
+
1967
+ this.children_ = []; // TODO: rename
1968
+ this.suites = []; // TODO: needed?
1969
+ this.specs = []; // TODO: needed?
1970
+
1971
+ this.result = {
1972
+ id: this.id,
1973
+ status: this.disabled ? 'disabled' : '',
1974
+ description: this.description,
1975
+ fullName: this.getFullName()
1976
+ };
1977
+ };
1978
+
1979
+ jasmine.Suite.prototype.getFullName = function() {
1980
+ var fullName = this.description;
1981
+ for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
1982
+ if (parentSuite.parentSuite) {
1983
+ fullName = parentSuite.description + ' ' + fullName;
1984
+ }
1985
+ }
1986
+ return fullName;
1987
+ };
1988
+
1989
+ jasmine.Suite.prototype.disable = function() {
1990
+ this.disabled = true;
1991
+ };
1992
+
1993
+ jasmine.Suite.prototype.beforeEach = function(fn) {
1994
+ this.beforeFns.unshift(fn);
1995
+ };
1996
+
1997
+ jasmine.Suite.prototype.afterEach = function(fn) {
1998
+ this.afterFns.unshift(fn);
1999
+ };
2000
+
2001
+ jasmine.Suite.prototype.addSpec = function(spec) {
2002
+ this.children_.push(spec);
2003
+ this.specs.push(spec); // TODO: needed?
2004
+ };
2005
+
2006
+ jasmine.Suite.prototype.addSuite = function(suite) {
2007
+ suite.parentSuite = this;
2008
+ this.children_.push(suite);
2009
+ this.suites.push(suite); // TODO: needed?
2010
+ };
2011
+
2012
+ jasmine.Suite.prototype.children = function() {
2013
+ return this.children_;
2014
+ };
2015
+
2016
+ jasmine.Suite.prototype.execute = function(onComplete) {
2017
+ var self = this;
2018
+ if (this.disabled) {
2019
+ complete();
2020
+ return;
2021
+ }
2022
+
2023
+ var allFns = [],
2024
+ children = this.children_;
2025
+
2026
+ for (var i = 0; i < children.length; i++) {
2027
+ allFns.push(wrapChild(children[i]));
2028
+ }
2029
+
2030
+ this.onStart(this);
2031
+
2032
+ this.queueRunner({
2033
+ fns: allFns,
2034
+ onComplete: complete
2035
+ });
2036
+
2037
+ function complete() {
2038
+ self.resultCallback(self.result);
2039
+
2040
+ if (onComplete) {
2041
+ onComplete();
2042
+ }
2043
+ }
2044
+
2045
+ function wrapChild(child) {
2046
+ return function (done) {
2047
+ child.execute(done);
2048
+ };
2049
+ }
2050
+ };
2051
+
2052
+ jasmine.version = "2.0.0-alpha";
2053
+
2054
+ if (module) module.exports = jasmine;