teaspoon 0.9.1 → 1.0.0

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