netzke-testing 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +106 -0
  6. data/Rakefile +1 -0
  7. data/app/assets/javascripts/netzke/.keep +0 -0
  8. data/app/assets/javascripts/netzke/testing/helpers/actions.js.coffee +74 -0
  9. data/app/assets/javascripts/netzke/testing/helpers/expectations.js.coffee +14 -0
  10. data/app/assets/javascripts/netzke/testing/helpers/form.js.coffee +7 -0
  11. data/app/assets/javascripts/netzke/testing/helpers/grid.js.coffee +107 -0
  12. data/app/assets/javascripts/netzke/testing/helpers/queries.js.coffee +88 -0
  13. data/app/assets/vendor/javascripts/expect/expect.js +1253 -0
  14. data/app/assets/vendor/javascripts/mocha/mocha.js +5340 -0
  15. data/app/assets/vendor/stylesheets/mocha/mocha.css +231 -0
  16. data/app/controllers/.keep +0 -0
  17. data/app/controllers/netzke/netzke/testing_controller.rb +28 -0
  18. data/app/helpers/.keep +0 -0
  19. data/app/helpers/netzke_testing_helper.rb +2 -0
  20. data/app/mailers/.keep +0 -0
  21. data/app/models/.keep +0 -0
  22. data/app/views/.keep +0 -0
  23. data/app/views/layouts/netzke/testing.html.erb +35 -0
  24. data/app/views/netzke/index.html.erb +2 -0
  25. data/config/routes.rb +8 -0
  26. data/lib/netzke/testing/engine.rb +6 -0
  27. data/lib/netzke/testing/helpers.rb +47 -0
  28. data/lib/netzke/testing/version.rb +5 -0
  29. data/lib/netzke/testing.rb +22 -0
  30. data/lib/netzke-testing.rb +1 -0
  31. data/netzke-testing.gemspec +23 -0
  32. data/test/controllers/netzke_testing_controller_test.rb +9 -0
  33. data/test/dummy/README.rdoc +28 -0
  34. data/test/dummy/Rakefile +6 -0
  35. data/test/dummy/app/assets/images/.keep +0 -0
  36. data/test/dummy/app/assets/javascripts/application.js +13 -0
  37. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  38. data/test/dummy/app/components/foo.rb +6 -0
  39. data/test/dummy/app/controllers/application_controller.rb +5 -0
  40. data/test/dummy/app/controllers/concerns/.keep +0 -0
  41. data/test/dummy/app/helpers/application_helper.rb +2 -0
  42. data/test/dummy/app/mailers/.keep +0 -0
  43. data/test/dummy/app/models/.keep +0 -0
  44. data/test/dummy/app/models/concerns/.keep +0 -0
  45. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  46. data/test/dummy/bin/bundle +3 -0
  47. data/test/dummy/bin/rails +4 -0
  48. data/test/dummy/bin/rake +4 -0
  49. data/test/dummy/config/application.rb +24 -0
  50. data/test/dummy/config/boot.rb +5 -0
  51. data/test/dummy/config/database.yml +25 -0
  52. data/test/dummy/config/environment.rb +5 -0
  53. data/test/dummy/config/environments/development.rb +23 -0
  54. data/test/dummy/config/environments/production.rb +80 -0
  55. data/test/dummy/config/environments/test.rb +36 -0
  56. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  57. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  58. data/test/dummy/config/initializers/inflections.rb +16 -0
  59. data/test/dummy/config/initializers/mime_types.rb +5 -0
  60. data/test/dummy/config/initializers/secret_token.rb +12 -0
  61. data/test/dummy/config/initializers/session_store.rb +3 -0
  62. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  63. data/test/dummy/config/locales/en.yml +23 -0
  64. data/test/dummy/config/routes.rb +58 -0
  65. data/test/dummy/config.ru +4 -0
  66. data/test/dummy/lib/assets/.keep +0 -0
  67. data/test/dummy/log/.keep +0 -0
  68. data/test/dummy/public/404.html +58 -0
  69. data/test/dummy/public/422.html +58 -0
  70. data/test/dummy/public/500.html +57 -0
  71. data/test/dummy/public/favicon.ico +0 -0
  72. data/test/dummy/spec/javascripts/foo.js.coffee +3 -0
  73. data/test/helpers/netzke_testing_helper_test.rb +4 -0
  74. data/test/integration/navigation_test.rb +10 -0
  75. data/test/netzke_testing_test.rb +7 -0
  76. data/test/test_helper.rb +15 -0
  77. metadata +193 -0
@@ -0,0 +1,1253 @@
1
+
2
+ (function (global, module) {
3
+
4
+ if ('undefined' == typeof module) {
5
+ var module = { exports: {} }
6
+ , exports = module.exports
7
+ }
8
+
9
+ /**
10
+ * Exports.
11
+ */
12
+
13
+ module.exports = expect;
14
+ expect.Assertion = Assertion;
15
+
16
+ /**
17
+ * Exports version.
18
+ */
19
+
20
+ expect.version = '0.1.2';
21
+
22
+ /**
23
+ * Possible assertion flags.
24
+ */
25
+
26
+ var flags = {
27
+ not: ['to', 'be', 'have', 'include', 'only']
28
+ , to: ['be', 'have', 'include', 'only', 'not']
29
+ , only: ['have']
30
+ , have: ['own']
31
+ , be: ['an']
32
+ };
33
+
34
+ function expect (obj) {
35
+ return new Assertion(obj);
36
+ }
37
+
38
+ /**
39
+ * Constructor
40
+ *
41
+ * @api private
42
+ */
43
+
44
+ function Assertion (obj, flag, parent) {
45
+ this.obj = obj;
46
+ this.flags = {};
47
+
48
+ if (undefined != parent) {
49
+ this.flags[flag] = true;
50
+
51
+ for (var i in parent.flags) {
52
+ if (parent.flags.hasOwnProperty(i)) {
53
+ this.flags[i] = true;
54
+ }
55
+ }
56
+ }
57
+
58
+ var $flags = flag ? flags[flag] : keys(flags)
59
+ , self = this
60
+
61
+ if ($flags) {
62
+ for (var i = 0, l = $flags.length; i < l; i++) {
63
+ // avoid recursion
64
+ if (this.flags[$flags[i]]) continue;
65
+
66
+ var name = $flags[i]
67
+ , assertion = new Assertion(this.obj, name, this)
68
+
69
+ if ('function' == typeof Assertion.prototype[name]) {
70
+ // clone the function, make sure we dont touch the prot reference
71
+ var old = this[name];
72
+ this[name] = function () {
73
+ return old.apply(self, arguments);
74
+ }
75
+
76
+ for (var fn in Assertion.prototype) {
77
+ if (Assertion.prototype.hasOwnProperty(fn) && fn != name) {
78
+ this[name][fn] = bind(assertion[fn], assertion);
79
+ }
80
+ }
81
+ } else {
82
+ this[name] = assertion;
83
+ }
84
+ }
85
+ }
86
+ };
87
+
88
+ /**
89
+ * Performs an assertion
90
+ *
91
+ * @api private
92
+ */
93
+
94
+ Assertion.prototype.assert = function (truth, msg, error) {
95
+ var msg = this.flags.not ? error : msg
96
+ , ok = this.flags.not ? !truth : truth;
97
+
98
+ if (!ok) {
99
+ throw new Error(msg.call(this));
100
+ }
101
+
102
+ this.and = new Assertion(this.obj);
103
+ };
104
+
105
+ /**
106
+ * Check if the value is truthy
107
+ *
108
+ * @api public
109
+ */
110
+
111
+ Assertion.prototype.ok = function () {
112
+ this.assert(
113
+ !!this.obj
114
+ , function(){ return 'expected ' + i(this.obj) + ' to be truthy' }
115
+ , function(){ return 'expected ' + i(this.obj) + ' to be falsy' });
116
+ };
117
+
118
+ /**
119
+ * Assert that the function throws.
120
+ *
121
+ * @param {Function|RegExp} callback, or regexp to match error string against
122
+ * @api public
123
+ */
124
+
125
+ Assertion.prototype.throwError =
126
+ Assertion.prototype.throwException = function (fn) {
127
+ expect(this.obj).to.be.a('function');
128
+
129
+ var thrown = false
130
+ , not = this.flags.not
131
+
132
+ try {
133
+ this.obj();
134
+ } catch (e) {
135
+ if ('function' == typeof fn) {
136
+ fn(e);
137
+ } else if ('object' == typeof fn) {
138
+ var subject = 'string' == typeof e ? e : e.message;
139
+ if (not) {
140
+ expect(subject).to.not.match(fn);
141
+ } else {
142
+ expect(subject).to.match(fn);
143
+ }
144
+ }
145
+ thrown = true;
146
+ }
147
+
148
+ if ('object' == typeof fn && not) {
149
+ // in the presence of a matcher, ensure the `not` only applies to
150
+ // the matching.
151
+ this.flags.not = false;
152
+ }
153
+
154
+ var name = this.obj.name || 'fn';
155
+ this.assert(
156
+ thrown
157
+ , function(){ return 'expected ' + name + ' to throw an exception' }
158
+ , function(){ return 'expected ' + name + ' not to throw an exception' });
159
+ };
160
+
161
+ /**
162
+ * Checks if the array is empty.
163
+ *
164
+ * @api public
165
+ */
166
+
167
+ Assertion.prototype.empty = function () {
168
+ var expectation;
169
+
170
+ if ('object' == typeof this.obj && null !== this.obj && !isArray(this.obj)) {
171
+ if ('number' == typeof this.obj.length) {
172
+ expectation = !this.obj.length;
173
+ } else {
174
+ expectation = !keys(this.obj).length;
175
+ }
176
+ } else {
177
+ if ('string' != typeof this.obj) {
178
+ expect(this.obj).to.be.an('object');
179
+ }
180
+
181
+ expect(this.obj).to.have.property('length');
182
+ expectation = !this.obj.length;
183
+ }
184
+
185
+ this.assert(
186
+ expectation
187
+ , function(){ return 'expected ' + i(this.obj) + ' to be empty' }
188
+ , function(){ return 'expected ' + i(this.obj) + ' to not be empty' });
189
+ return this;
190
+ };
191
+
192
+ /**
193
+ * Checks if the obj exactly equals another.
194
+ *
195
+ * @api public
196
+ */
197
+
198
+ Assertion.prototype.be =
199
+ Assertion.prototype.equal = function (obj) {
200
+ this.assert(
201
+ obj === this.obj
202
+ , function(){ return 'expected ' + i(this.obj) + ' to equal ' + i(obj) }
203
+ , function(){ return 'expected ' + i(this.obj) + ' to not equal ' + i(obj) });
204
+ return this;
205
+ };
206
+
207
+ /**
208
+ * Checks if the obj sortof equals another.
209
+ *
210
+ * @api public
211
+ */
212
+
213
+ Assertion.prototype.eql = function (obj) {
214
+ this.assert(
215
+ expect.eql(obj, this.obj)
216
+ , function(){ return 'expected ' + i(this.obj) + ' to sort of equal ' + i(obj) }
217
+ , function(){ return 'expected ' + i(this.obj) + ' to sort of not equal ' + i(obj) });
218
+ return this;
219
+ };
220
+
221
+ /**
222
+ * Assert within start to finish (inclusive).
223
+ *
224
+ * @param {Number} start
225
+ * @param {Number} finish
226
+ * @api public
227
+ */
228
+
229
+ Assertion.prototype.within = function (start, finish) {
230
+ var range = start + '..' + finish;
231
+ this.assert(
232
+ this.obj >= start && this.obj <= finish
233
+ , function(){ return 'expected ' + i(this.obj) + ' to be within ' + range }
234
+ , function(){ return 'expected ' + i(this.obj) + ' to not be within ' + range });
235
+ return this;
236
+ };
237
+
238
+ /**
239
+ * Assert typeof / instance of
240
+ *
241
+ * @api public
242
+ */
243
+
244
+ Assertion.prototype.a =
245
+ Assertion.prototype.an = function (type) {
246
+ if ('string' == typeof type) {
247
+ // proper english in error msg
248
+ var n = /^[aeiou]/.test(type) ? 'n' : '';
249
+
250
+ // typeof with support for 'array'
251
+ this.assert(
252
+ 'array' == type ? isArray(this.obj) :
253
+ 'object' == type
254
+ ? 'object' == typeof this.obj && null !== this.obj
255
+ : type == typeof this.obj
256
+ , function(){ return 'expected ' + i(this.obj) + ' to be a' + n + ' ' + type }
257
+ , function(){ return 'expected ' + i(this.obj) + ' not to be a' + n + ' ' + type });
258
+ } else {
259
+ // instanceof
260
+ var name = type.name || 'supplied constructor';
261
+ this.assert(
262
+ this.obj instanceof type
263
+ , function(){ return 'expected ' + i(this.obj) + ' to be an instance of ' + name }
264
+ , function(){ return 'expected ' + i(this.obj) + ' not to be an instance of ' + name });
265
+ }
266
+
267
+ return this;
268
+ };
269
+
270
+ /**
271
+ * Assert numeric value above _n_.
272
+ *
273
+ * @param {Number} n
274
+ * @api public
275
+ */
276
+
277
+ Assertion.prototype.greaterThan =
278
+ Assertion.prototype.above = function (n) {
279
+ this.assert(
280
+ this.obj > n
281
+ , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n }
282
+ , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n });
283
+ return this;
284
+ };
285
+
286
+ /**
287
+ * Assert numeric value below _n_.
288
+ *
289
+ * @param {Number} n
290
+ * @api public
291
+ */
292
+
293
+ Assertion.prototype.lessThan =
294
+ Assertion.prototype.below = function (n) {
295
+ this.assert(
296
+ this.obj < n
297
+ , function(){ return 'expected ' + i(this.obj) + ' to be below ' + n }
298
+ , function(){ return 'expected ' + i(this.obj) + ' to be above ' + n });
299
+ return this;
300
+ };
301
+
302
+ /**
303
+ * Assert string value matches _regexp_.
304
+ *
305
+ * @param {RegExp} regexp
306
+ * @api public
307
+ */
308
+
309
+ Assertion.prototype.match = function (regexp) {
310
+ this.assert(
311
+ regexp.exec(this.obj)
312
+ , function(){ return 'expected ' + i(this.obj) + ' to match ' + regexp }
313
+ , function(){ return 'expected ' + i(this.obj) + ' not to match ' + regexp });
314
+ return this;
315
+ };
316
+
317
+ /**
318
+ * Assert property "length" exists and has value of _n_.
319
+ *
320
+ * @param {Number} n
321
+ * @api public
322
+ */
323
+
324
+ Assertion.prototype.length = function (n) {
325
+ expect(this.obj).to.have.property('length');
326
+ var len = this.obj.length;
327
+ this.assert(
328
+ n == len
329
+ , function(){ return 'expected ' + i(this.obj) + ' to have a length of ' + n + ' but got ' + len }
330
+ , function(){ return 'expected ' + i(this.obj) + ' to not have a length of ' + len });
331
+ return this;
332
+ };
333
+
334
+ /**
335
+ * Assert property _name_ exists, with optional _val_.
336
+ *
337
+ * @param {String} name
338
+ * @param {Mixed} val
339
+ * @api public
340
+ */
341
+
342
+ Assertion.prototype.property = function (name, val) {
343
+ if (this.flags.own) {
344
+ this.assert(
345
+ Object.prototype.hasOwnProperty.call(this.obj, name)
346
+ , function(){ return 'expected ' + i(this.obj) + ' to have own property ' + i(name) }
347
+ , function(){ return 'expected ' + i(this.obj) + ' to not have own property ' + i(name) });
348
+ return this;
349
+ }
350
+
351
+ if (this.flags.not && undefined !== val) {
352
+ if (undefined === this.obj[name]) {
353
+ throw new Error(i(this.obj) + ' has no property ' + i(name));
354
+ }
355
+ } else {
356
+ var hasProp;
357
+ try {
358
+ hasProp = name in this.obj
359
+ } catch (e) {
360
+ hasProp = undefined !== this.obj[name]
361
+ }
362
+
363
+ this.assert(
364
+ hasProp
365
+ , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) }
366
+ , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) });
367
+ }
368
+
369
+ if (undefined !== val) {
370
+ this.assert(
371
+ val === this.obj[name]
372
+ , function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name)
373
+ + ' of ' + i(val) + ', but got ' + i(this.obj[name]) }
374
+ , function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name)
375
+ + ' of ' + i(val) });
376
+ }
377
+
378
+ this.obj = this.obj[name];
379
+ return this;
380
+ };
381
+
382
+ /**
383
+ * Assert that the array contains _obj_ or string contains _obj_.
384
+ *
385
+ * @param {Mixed} obj|string
386
+ * @api public
387
+ */
388
+
389
+ Assertion.prototype.string =
390
+ Assertion.prototype.contain = function (obj) {
391
+ if ('string' == typeof this.obj) {
392
+ this.assert(
393
+ ~this.obj.indexOf(obj)
394
+ , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }
395
+ , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });
396
+ } else {
397
+ this.assert(
398
+ ~indexOf(this.obj, obj)
399
+ , function(){ return 'expected ' + i(this.obj) + ' to contain ' + i(obj) }
400
+ , function(){ return 'expected ' + i(this.obj) + ' to not contain ' + i(obj) });
401
+ }
402
+ return this;
403
+ };
404
+
405
+ /**
406
+ * Assert exact keys or inclusion of keys by using
407
+ * the `.own` modifier.
408
+ *
409
+ * @param {Array|String ...} keys
410
+ * @api public
411
+ */
412
+
413
+ Assertion.prototype.key =
414
+ Assertion.prototype.keys = function ($keys) {
415
+ var str
416
+ , ok = true;
417
+
418
+ $keys = isArray($keys)
419
+ ? $keys
420
+ : Array.prototype.slice.call(arguments);
421
+
422
+ if (!$keys.length) throw new Error('keys required');
423
+
424
+ var actual = keys(this.obj)
425
+ , len = $keys.length;
426
+
427
+ // Inclusion
428
+ ok = every($keys, function (key) {
429
+ return ~indexOf(actual, key);
430
+ });
431
+
432
+ // Strict
433
+ if (!this.flags.not && this.flags.only) {
434
+ ok = ok && $keys.length == actual.length;
435
+ }
436
+
437
+ // Key string
438
+ if (len > 1) {
439
+ $keys = map($keys, function (key) {
440
+ return i(key);
441
+ });
442
+ var last = $keys.pop();
443
+ str = $keys.join(', ') + ', and ' + last;
444
+ } else {
445
+ str = i($keys[0]);
446
+ }
447
+
448
+ // Form
449
+ str = (len > 1 ? 'keys ' : 'key ') + str;
450
+
451
+ // Have / include
452
+ str = (!this.flags.only ? 'include ' : 'only have ') + str;
453
+
454
+ // Assertion
455
+ this.assert(
456
+ ok
457
+ , function(){ return 'expected ' + i(this.obj) + ' to ' + str }
458
+ , function(){ return 'expected ' + i(this.obj) + ' to not ' + str });
459
+
460
+ return this;
461
+ };
462
+ /**
463
+ * Assert a failure.
464
+ *
465
+ * @param {String ...} custom message
466
+ * @api public
467
+ */
468
+ Assertion.prototype.fail = function (msg) {
469
+ msg = msg || "explicit failure";
470
+ this.assert(false, msg, msg);
471
+ return this;
472
+ };
473
+
474
+ /**
475
+ * Function bind implementation.
476
+ */
477
+
478
+ function bind (fn, scope) {
479
+ return function () {
480
+ return fn.apply(scope, arguments);
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Array every compatibility
486
+ *
487
+ * @see bit.ly/5Fq1N2
488
+ * @api public
489
+ */
490
+
491
+ function every (arr, fn, thisObj) {
492
+ var scope = thisObj || global;
493
+ for (var i = 0, j = arr.length; i < j; ++i) {
494
+ if (!fn.call(scope, arr[i], i, arr)) {
495
+ return false;
496
+ }
497
+ }
498
+ return true;
499
+ };
500
+
501
+ /**
502
+ * Array indexOf compatibility.
503
+ *
504
+ * @see bit.ly/a5Dxa2
505
+ * @api public
506
+ */
507
+
508
+ function indexOf (arr, o, i) {
509
+ if (Array.prototype.indexOf) {
510
+ return Array.prototype.indexOf.call(arr, o, i);
511
+ }
512
+
513
+ if (arr.length === undefined) {
514
+ return -1;
515
+ }
516
+
517
+ for (var j = arr.length, i = i < 0 ? i + j < 0 ? 0 : i + j : i || 0
518
+ ; i < j && arr[i] !== o; i++);
519
+
520
+ return j <= i ? -1 : i;
521
+ };
522
+
523
+ // https://gist.github.com/1044128/
524
+ var getOuterHTML = function(element) {
525
+ if ('outerHTML' in element) return element.outerHTML;
526
+ var ns = "http://www.w3.org/1999/xhtml";
527
+ var container = document.createElementNS(ns, '_');
528
+ var elemProto = (window.HTMLElement || window.Element).prototype;
529
+ var xmlSerializer = new XMLSerializer();
530
+ var html;
531
+ if (document.xmlVersion) {
532
+ return xmlSerializer.serializeToString(element);
533
+ } else {
534
+ container.appendChild(element.cloneNode(false));
535
+ html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');
536
+ container.innerHTML = '';
537
+ return html;
538
+ }
539
+ };
540
+
541
+ // Returns true if object is a DOM element.
542
+ var isDOMElement = function (object) {
543
+ if (typeof HTMLElement === 'object') {
544
+ return object instanceof HTMLElement;
545
+ } else {
546
+ return object &&
547
+ typeof object === 'object' &&
548
+ object.nodeType === 1 &&
549
+ typeof object.nodeName === 'string';
550
+ }
551
+ };
552
+
553
+ /**
554
+ * Inspects an object.
555
+ *
556
+ * @see taken from node.js `util` module (copyright Joyent, MIT license)
557
+ * @api private
558
+ */
559
+
560
+ function i (obj, showHidden, depth) {
561
+ var seen = [];
562
+
563
+ function stylize (str) {
564
+ return str;
565
+ };
566
+
567
+ function format (value, recurseTimes) {
568
+ // Provide a hook for user-specified inspect functions.
569
+ // Check that value is an object with an inspect function on it
570
+ if (value && typeof value.inspect === 'function' &&
571
+ // Filter out the util module, it's inspect function is special
572
+ value !== exports &&
573
+ // Also filter out any prototype objects using the circular check.
574
+ !(value.constructor && value.constructor.prototype === value)) {
575
+ return value.inspect(recurseTimes);
576
+ }
577
+
578
+ // Primitive types cannot have properties
579
+ switch (typeof value) {
580
+ case 'undefined':
581
+ return stylize('undefined', 'undefined');
582
+
583
+ case 'string':
584
+ var simple = '\'' + json.stringify(value).replace(/^"|"$/g, '')
585
+ .replace(/'/g, "\\'")
586
+ .replace(/\\"/g, '"') + '\'';
587
+ return stylize(simple, 'string');
588
+
589
+ case 'number':
590
+ return stylize('' + value, 'number');
591
+
592
+ case 'boolean':
593
+ return stylize('' + value, 'boolean');
594
+ }
595
+ // For some reason typeof null is "object", so special case here.
596
+ if (value === null) {
597
+ return stylize('null', 'null');
598
+ }
599
+
600
+ if (isDOMElement(value)) {
601
+ return getOuterHTML(value);
602
+ }
603
+
604
+ // Look up the keys of the object.
605
+ var visible_keys = keys(value);
606
+ var $keys = showHidden ? Object.getOwnPropertyNames(value) : visible_keys;
607
+
608
+ // Functions without properties can be shortcutted.
609
+ if (typeof value === 'function' && $keys.length === 0) {
610
+ if (isRegExp(value)) {
611
+ return stylize('' + value, 'regexp');
612
+ } else {
613
+ var name = value.name ? ': ' + value.name : '';
614
+ return stylize('[Function' + name + ']', 'special');
615
+ }
616
+ }
617
+
618
+ // Dates without properties can be shortcutted
619
+ if (isDate(value) && $keys.length === 0) {
620
+ return stylize(value.toUTCString(), 'date');
621
+ }
622
+
623
+ var base, type, braces;
624
+ // Determine the object type
625
+ if (isArray(value)) {
626
+ type = 'Array';
627
+ braces = ['[', ']'];
628
+ } else {
629
+ type = 'Object';
630
+ braces = ['{', '}'];
631
+ }
632
+
633
+ // Make functions say that they are functions
634
+ if (typeof value === 'function') {
635
+ var n = value.name ? ': ' + value.name : '';
636
+ base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';
637
+ } else {
638
+ base = '';
639
+ }
640
+
641
+ // Make dates with properties first say the date
642
+ if (isDate(value)) {
643
+ base = ' ' + value.toUTCString();
644
+ }
645
+
646
+ if ($keys.length === 0) {
647
+ return braces[0] + base + braces[1];
648
+ }
649
+
650
+ if (recurseTimes < 0) {
651
+ if (isRegExp(value)) {
652
+ return stylize('' + value, 'regexp');
653
+ } else {
654
+ return stylize('[Object]', 'special');
655
+ }
656
+ }
657
+
658
+ seen.push(value);
659
+
660
+ var output = map($keys, function (key) {
661
+ var name, str;
662
+ if (value.__lookupGetter__) {
663
+ if (value.__lookupGetter__(key)) {
664
+ if (value.__lookupSetter__(key)) {
665
+ str = stylize('[Getter/Setter]', 'special');
666
+ } else {
667
+ str = stylize('[Getter]', 'special');
668
+ }
669
+ } else {
670
+ if (value.__lookupSetter__(key)) {
671
+ str = stylize('[Setter]', 'special');
672
+ }
673
+ }
674
+ }
675
+ if (indexOf(visible_keys, key) < 0) {
676
+ name = '[' + key + ']';
677
+ }
678
+ if (!str) {
679
+ if (indexOf(seen, value[key]) < 0) {
680
+ if (recurseTimes === null) {
681
+ str = format(value[key]);
682
+ } else {
683
+ str = format(value[key], recurseTimes - 1);
684
+ }
685
+ if (str.indexOf('\n') > -1) {
686
+ if (isArray(value)) {
687
+ str = map(str.split('\n'), function (line) {
688
+ return ' ' + line;
689
+ }).join('\n').substr(2);
690
+ } else {
691
+ str = '\n' + map(str.split('\n'), function (line) {
692
+ return ' ' + line;
693
+ }).join('\n');
694
+ }
695
+ }
696
+ } else {
697
+ str = stylize('[Circular]', 'special');
698
+ }
699
+ }
700
+ if (typeof name === 'undefined') {
701
+ if (type === 'Array' && key.match(/^\d+$/)) {
702
+ return str;
703
+ }
704
+ name = json.stringify('' + key);
705
+ if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
706
+ name = name.substr(1, name.length - 2);
707
+ name = stylize(name, 'name');
708
+ } else {
709
+ name = name.replace(/'/g, "\\'")
710
+ .replace(/\\"/g, '"')
711
+ .replace(/(^"|"$)/g, "'");
712
+ name = stylize(name, 'string');
713
+ }
714
+ }
715
+
716
+ return name + ': ' + str;
717
+ });
718
+
719
+ seen.pop();
720
+
721
+ var numLinesEst = 0;
722
+ var length = reduce(output, function (prev, cur) {
723
+ numLinesEst++;
724
+ if (indexOf(cur, '\n') >= 0) numLinesEst++;
725
+ return prev + cur.length + 1;
726
+ }, 0);
727
+
728
+ if (length > 50) {
729
+ output = braces[0] +
730
+ (base === '' ? '' : base + '\n ') +
731
+ ' ' +
732
+ output.join(',\n ') +
733
+ ' ' +
734
+ braces[1];
735
+
736
+ } else {
737
+ output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
738
+ }
739
+
740
+ return output;
741
+ }
742
+ return format(obj, (typeof depth === 'undefined' ? 2 : depth));
743
+ };
744
+
745
+ function isArray (ar) {
746
+ return Object.prototype.toString.call(ar) == '[object Array]';
747
+ };
748
+
749
+ function isRegExp(re) {
750
+ var s;
751
+ try {
752
+ s = '' + re;
753
+ } catch (e) {
754
+ return false;
755
+ }
756
+
757
+ return re instanceof RegExp || // easy case
758
+ // duck-type for context-switching evalcx case
759
+ typeof(re) === 'function' &&
760
+ re.constructor.name === 'RegExp' &&
761
+ re.compile &&
762
+ re.test &&
763
+ re.exec &&
764
+ s.match(/^\/.*\/[gim]{0,3}$/);
765
+ };
766
+
767
+ function isDate(d) {
768
+ if (d instanceof Date) return true;
769
+ return false;
770
+ };
771
+
772
+ function keys (obj) {
773
+ if (Object.keys) {
774
+ return Object.keys(obj);
775
+ }
776
+
777
+ var keys = [];
778
+
779
+ for (var i in obj) {
780
+ if (Object.prototype.hasOwnProperty.call(obj, i)) {
781
+ keys.push(i);
782
+ }
783
+ }
784
+
785
+ return keys;
786
+ }
787
+
788
+ function map (arr, mapper, that) {
789
+ if (Array.prototype.map) {
790
+ return Array.prototype.map.call(arr, mapper, that);
791
+ }
792
+
793
+ var other= new Array(arr.length);
794
+
795
+ for (var i= 0, n = arr.length; i<n; i++)
796
+ if (i in arr)
797
+ other[i] = mapper.call(that, arr[i], i, arr);
798
+
799
+ return other;
800
+ };
801
+
802
+ function reduce (arr, fun) {
803
+ if (Array.prototype.reduce) {
804
+ return Array.prototype.reduce.apply(
805
+ arr
806
+ , Array.prototype.slice.call(arguments, 1)
807
+ );
808
+ }
809
+
810
+ var len = +this.length;
811
+
812
+ if (typeof fun !== "function")
813
+ throw new TypeError();
814
+
815
+ // no value to return if no initial value and an empty array
816
+ if (len === 0 && arguments.length === 1)
817
+ throw new TypeError();
818
+
819
+ var i = 0;
820
+ if (arguments.length >= 2) {
821
+ var rv = arguments[1];
822
+ } else {
823
+ do {
824
+ if (i in this) {
825
+ rv = this[i++];
826
+ break;
827
+ }
828
+
829
+ // if array contains no values, no initial value to return
830
+ if (++i >= len)
831
+ throw new TypeError();
832
+ } while (true);
833
+ }
834
+
835
+ for (; i < len; i++) {
836
+ if (i in this)
837
+ rv = fun.call(null, rv, this[i], i, this);
838
+ }
839
+
840
+ return rv;
841
+ };
842
+
843
+ /**
844
+ * Asserts deep equality
845
+ *
846
+ * @see taken from node.js `assert` module (copyright Joyent, MIT license)
847
+ * @api private
848
+ */
849
+
850
+ expect.eql = function eql (actual, expected) {
851
+ // 7.1. All identical values are equivalent, as determined by ===.
852
+ if (actual === expected) {
853
+ return true;
854
+ } else if ('undefined' != typeof Buffer
855
+ && Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
856
+ if (actual.length != expected.length) return false;
857
+
858
+ for (var i = 0; i < actual.length; i++) {
859
+ if (actual[i] !== expected[i]) return false;
860
+ }
861
+
862
+ return true;
863
+
864
+ // 7.2. If the expected value is a Date object, the actual value is
865
+ // equivalent if it is also a Date object that refers to the same time.
866
+ } else if (actual instanceof Date && expected instanceof Date) {
867
+ return actual.getTime() === expected.getTime();
868
+
869
+ // 7.3. Other pairs that do not both pass typeof value == "object",
870
+ // equivalence is determined by ==.
871
+ } else if (typeof actual != 'object' && typeof expected != 'object') {
872
+ return actual == expected;
873
+
874
+ // 7.4. For all other Object pairs, including Array objects, equivalence is
875
+ // determined by having the same number of owned properties (as verified
876
+ // with Object.prototype.hasOwnProperty.call), the same set of keys
877
+ // (although not necessarily the same order), equivalent values for every
878
+ // corresponding key, and an identical "prototype" property. Note: this
879
+ // accounts for both named and indexed properties on Arrays.
880
+ } else {
881
+ return objEquiv(actual, expected);
882
+ }
883
+ }
884
+
885
+ function isUndefinedOrNull (value) {
886
+ return value === null || value === undefined;
887
+ }
888
+
889
+ function isArguments (object) {
890
+ return Object.prototype.toString.call(object) == '[object Arguments]';
891
+ }
892
+
893
+ function objEquiv (a, b) {
894
+ if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
895
+ return false;
896
+ // an identical "prototype" property.
897
+ if (a.prototype !== b.prototype) return false;
898
+ //~~~I've managed to break Object.keys through screwy arguments passing.
899
+ // Converting to array solves the problem.
900
+ if (isArguments(a)) {
901
+ if (!isArguments(b)) {
902
+ return false;
903
+ }
904
+ a = pSlice.call(a);
905
+ b = pSlice.call(b);
906
+ return expect.eql(a, b);
907
+ }
908
+ try{
909
+ var ka = keys(a),
910
+ kb = keys(b),
911
+ key, i;
912
+ } catch (e) {//happens when one is a string literal and the other isn't
913
+ return false;
914
+ }
915
+ // having the same number of owned properties (keys incorporates hasOwnProperty)
916
+ if (ka.length != kb.length)
917
+ return false;
918
+ //the same set of keys (although not necessarily the same order),
919
+ ka.sort();
920
+ kb.sort();
921
+ //~~~cheap key test
922
+ for (i = ka.length - 1; i >= 0; i--) {
923
+ if (ka[i] != kb[i])
924
+ return false;
925
+ }
926
+ //equivalent values for every corresponding key, and
927
+ //~~~possibly expensive deep test
928
+ for (i = ka.length - 1; i >= 0; i--) {
929
+ key = ka[i];
930
+ if (!expect.eql(a[key], b[key]))
931
+ return false;
932
+ }
933
+ return true;
934
+ }
935
+
936
+ var json = (function () {
937
+ "use strict";
938
+
939
+ if ('object' == typeof JSON && JSON.parse && JSON.stringify) {
940
+ return {
941
+ parse: nativeJSON.parse
942
+ , stringify: nativeJSON.stringify
943
+ }
944
+ }
945
+
946
+ var JSON = {};
947
+
948
+ function f(n) {
949
+ // Format integers to have at least two digits.
950
+ return n < 10 ? '0' + n : n;
951
+ }
952
+
953
+ function date(d, key) {
954
+ return isFinite(d.valueOf()) ?
955
+ d.getUTCFullYear() + '-' +
956
+ f(d.getUTCMonth() + 1) + '-' +
957
+ f(d.getUTCDate()) + 'T' +
958
+ f(d.getUTCHours()) + ':' +
959
+ f(d.getUTCMinutes()) + ':' +
960
+ f(d.getUTCSeconds()) + 'Z' : null;
961
+ };
962
+
963
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
964
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
965
+ gap,
966
+ indent,
967
+ meta = { // table of character substitutions
968
+ '\b': '\\b',
969
+ '\t': '\\t',
970
+ '\n': '\\n',
971
+ '\f': '\\f',
972
+ '\r': '\\r',
973
+ '"' : '\\"',
974
+ '\\': '\\\\'
975
+ },
976
+ rep;
977
+
978
+
979
+ function quote(string) {
980
+
981
+ // If the string contains no control characters, no quote characters, and no
982
+ // backslash characters, then we can safely slap some quotes around it.
983
+ // Otherwise we must also replace the offending characters with safe escape
984
+ // sequences.
985
+
986
+ escapable.lastIndex = 0;
987
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
988
+ var c = meta[a];
989
+ return typeof c === 'string' ? c :
990
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
991
+ }) + '"' : '"' + string + '"';
992
+ }
993
+
994
+
995
+ function str(key, holder) {
996
+
997
+ // Produce a string from holder[key].
998
+
999
+ var i, // The loop counter.
1000
+ k, // The member key.
1001
+ v, // The member value.
1002
+ length,
1003
+ mind = gap,
1004
+ partial,
1005
+ value = holder[key];
1006
+
1007
+ // If the value has a toJSON method, call it to obtain a replacement value.
1008
+
1009
+ if (value instanceof Date) {
1010
+ value = date(key);
1011
+ }
1012
+
1013
+ // If we were called with a replacer function, then call the replacer to
1014
+ // obtain a replacement value.
1015
+
1016
+ if (typeof rep === 'function') {
1017
+ value = rep.call(holder, key, value);
1018
+ }
1019
+
1020
+ // What happens next depends on the value's type.
1021
+
1022
+ switch (typeof value) {
1023
+ case 'string':
1024
+ return quote(value);
1025
+
1026
+ case 'number':
1027
+
1028
+ // JSON numbers must be finite. Encode non-finite numbers as null.
1029
+
1030
+ return isFinite(value) ? String(value) : 'null';
1031
+
1032
+ case 'boolean':
1033
+ case 'null':
1034
+
1035
+ // If the value is a boolean or null, convert it to a string. Note:
1036
+ // typeof null does not produce 'null'. The case is included here in
1037
+ // the remote chance that this gets fixed someday.
1038
+
1039
+ return String(value);
1040
+
1041
+ // If the type is 'object', we might be dealing with an object or an array or
1042
+ // null.
1043
+
1044
+ case 'object':
1045
+
1046
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
1047
+ // so watch out for that case.
1048
+
1049
+ if (!value) {
1050
+ return 'null';
1051
+ }
1052
+
1053
+ // Make an array to hold the partial results of stringifying this object value.
1054
+
1055
+ gap += indent;
1056
+ partial = [];
1057
+
1058
+ // Is the value an array?
1059
+
1060
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
1061
+
1062
+ // The value is an array. Stringify every element. Use null as a placeholder
1063
+ // for non-JSON values.
1064
+
1065
+ length = value.length;
1066
+ for (i = 0; i < length; i += 1) {
1067
+ partial[i] = str(i, value) || 'null';
1068
+ }
1069
+
1070
+ // Join all of the elements together, separated with commas, and wrap them in
1071
+ // brackets.
1072
+
1073
+ v = partial.length === 0 ? '[]' : gap ?
1074
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
1075
+ '[' + partial.join(',') + ']';
1076
+ gap = mind;
1077
+ return v;
1078
+ }
1079
+
1080
+ // If the replacer is an array, use it to select the members to be stringified.
1081
+
1082
+ if (rep && typeof rep === 'object') {
1083
+ length = rep.length;
1084
+ for (i = 0; i < length; i += 1) {
1085
+ if (typeof rep[i] === 'string') {
1086
+ k = rep[i];
1087
+ v = str(k, value);
1088
+ if (v) {
1089
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1090
+ }
1091
+ }
1092
+ }
1093
+ } else {
1094
+
1095
+ // Otherwise, iterate through all of the keys in the object.
1096
+
1097
+ for (k in value) {
1098
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1099
+ v = str(k, value);
1100
+ if (v) {
1101
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1102
+ }
1103
+ }
1104
+ }
1105
+ }
1106
+
1107
+ // Join all of the member texts together, separated with commas,
1108
+ // and wrap them in braces.
1109
+
1110
+ v = partial.length === 0 ? '{}' : gap ?
1111
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
1112
+ '{' + partial.join(',') + '}';
1113
+ gap = mind;
1114
+ return v;
1115
+ }
1116
+ }
1117
+
1118
+ // If the JSON object does not yet have a stringify method, give it one.
1119
+
1120
+ JSON.stringify = function (value, replacer, space) {
1121
+
1122
+ // The stringify method takes a value and an optional replacer, and an optional
1123
+ // space parameter, and returns a JSON text. The replacer can be a function
1124
+ // that can replace values, or an array of strings that will select the keys.
1125
+ // A default replacer method can be provided. Use of the space parameter can
1126
+ // produce text that is more easily readable.
1127
+
1128
+ var i;
1129
+ gap = '';
1130
+ indent = '';
1131
+
1132
+ // If the space parameter is a number, make an indent string containing that
1133
+ // many spaces.
1134
+
1135
+ if (typeof space === 'number') {
1136
+ for (i = 0; i < space; i += 1) {
1137
+ indent += ' ';
1138
+ }
1139
+
1140
+ // If the space parameter is a string, it will be used as the indent string.
1141
+
1142
+ } else if (typeof space === 'string') {
1143
+ indent = space;
1144
+ }
1145
+
1146
+ // If there is a replacer, it must be a function or an array.
1147
+ // Otherwise, throw an error.
1148
+
1149
+ rep = replacer;
1150
+ if (replacer && typeof replacer !== 'function' &&
1151
+ (typeof replacer !== 'object' ||
1152
+ typeof replacer.length !== 'number')) {
1153
+ throw new Error('JSON.stringify');
1154
+ }
1155
+
1156
+ // Make a fake root object containing our value under the key of ''.
1157
+ // Return the result of stringifying the value.
1158
+
1159
+ return str('', {'': value});
1160
+ };
1161
+
1162
+ // If the JSON object does not yet have a parse method, give it one.
1163
+
1164
+ JSON.parse = function (text, reviver) {
1165
+ // The parse method takes a text and an optional reviver function, and returns
1166
+ // a JavaScript value if the text is a valid JSON text.
1167
+
1168
+ var j;
1169
+
1170
+ function walk(holder, key) {
1171
+
1172
+ // The walk method is used to recursively walk the resulting structure so
1173
+ // that modifications can be made.
1174
+
1175
+ var k, v, value = holder[key];
1176
+ if (value && typeof value === 'object') {
1177
+ for (k in value) {
1178
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1179
+ v = walk(value, k);
1180
+ if (v !== undefined) {
1181
+ value[k] = v;
1182
+ } else {
1183
+ delete value[k];
1184
+ }
1185
+ }
1186
+ }
1187
+ }
1188
+ return reviver.call(holder, key, value);
1189
+ }
1190
+
1191
+
1192
+ // Parsing happens in four stages. In the first stage, we replace certain
1193
+ // Unicode characters with escape sequences. JavaScript handles many characters
1194
+ // incorrectly, either silently deleting them, or treating them as line endings.
1195
+
1196
+ text = String(text);
1197
+ cx.lastIndex = 0;
1198
+ if (cx.test(text)) {
1199
+ text = text.replace(cx, function (a) {
1200
+ return '\\u' +
1201
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1202
+ });
1203
+ }
1204
+
1205
+ // In the second stage, we run the text against regular expressions that look
1206
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
1207
+ // because they can cause invocation, and '=' because it can cause mutation.
1208
+ // But just to be safe, we want to reject all unexpected forms.
1209
+
1210
+ // We split the second stage into 4 regexp operations in order to work around
1211
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
1212
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
1213
+ // replace all simple value tokens with ']' characters. Third, we delete all
1214
+ // open brackets that follow a colon or comma or that begin the text. Finally,
1215
+ // we look to see that the remaining characters are only whitespace or ']' or
1216
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
1217
+
1218
+ if (/^[\],:{}\s]*$/
1219
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
1220
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
1221
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
1222
+
1223
+ // In the third stage we use the eval function to compile the text into a
1224
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
1225
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
1226
+ // in parens to eliminate the ambiguity.
1227
+
1228
+ j = eval('(' + text + ')');
1229
+
1230
+ // In the optional fourth stage, we recursively walk the new structure, passing
1231
+ // each name/value pair to a reviver function for possible transformation.
1232
+
1233
+ return typeof reviver === 'function' ?
1234
+ walk({'': j}, '') : j;
1235
+ }
1236
+
1237
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
1238
+
1239
+ throw new SyntaxError('JSON.parse');
1240
+ };
1241
+
1242
+ return JSON;
1243
+ })();
1244
+
1245
+ if ('undefined' != typeof window) {
1246
+ window.expect = module.exports;
1247
+ }
1248
+
1249
+ })(
1250
+ this
1251
+ , 'undefined' != typeof module ? module : {}
1252
+ , 'undefined' != typeof exports ? exports : {}
1253
+ );