rhoconnect 3.1.2 → 3.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (248) hide show
  1. data/CHANGELOG.md +14 -2
  2. data/CREDITS +151 -10
  3. data/Gemfile +16 -5
  4. data/Gemfile.lock +58 -23
  5. data/Rakefile +70 -50
  6. data/bench/bench_runner.rb +2 -2
  7. data/bench/benchapp/Gemfile +6 -0
  8. data/bench/benchapp/Gemfile.lock +5 -0
  9. data/bench/benchapp/config.ru +2 -0
  10. data/bench/lib/bench/cli.rb +2 -0
  11. data/bench/lib/bench/distr_runner.rb +3 -2
  12. data/bench/lib/bench/runner.rb +1 -1
  13. data/bench/lib/bench.rb +10 -1
  14. data/bench/run_bench.sh +1 -1
  15. data/bench/scripts/test_query_script.rb +2 -1
  16. data/bench/spec/bench_spec_helper.rb +1 -0
  17. data/bin/rhoconnect +9 -27
  18. data/bin/rhoconnect-benchmark +10 -1
  19. data/commands/commands/dtach_commands/dtach_about.rb +6 -0
  20. data/commands/commands/dtach_commands/dtach_install.rb +30 -0
  21. data/commands/commands/redis_commands/redis_about.rb +6 -0
  22. data/commands/commands/redis_commands/redis_attach.rb +6 -0
  23. data/commands/commands/redis_commands/redis_download.rb +33 -0
  24. data/commands/commands/redis_commands/redis_install.rb +26 -0
  25. data/commands/commands/redis_commands/redis_make.rb +9 -0
  26. data/commands/commands/redis_commands/redis_restart.rb +7 -0
  27. data/commands/commands/redis_commands/redis_runner.rb +67 -0
  28. data/commands/commands/redis_commands/redis_start.rb +6 -0
  29. data/commands/commands/redis_commands/redis_startbg.rb +6 -0
  30. data/commands/commands/redis_commands/redis_stop.rb +6 -0
  31. data/commands/commands/rhoconnect/attach.rb +7 -0
  32. data/commands/commands/rhoconnect/clean_start.rb +9 -0
  33. data/commands/commands/rhoconnect/config.rb +15 -0
  34. data/commands/commands/rhoconnect/console.rb +15 -0
  35. data/commands/commands/rhoconnect/console_helper.rb +3 -0
  36. data/commands/commands/rhoconnect/create_user.rb +18 -0
  37. data/commands/commands/rhoconnect/delete_device.rb +9 -0
  38. data/commands/commands/rhoconnect/delete_user.rb +8 -0
  39. data/commands/commands/rhoconnect/flushdb.rb +14 -0
  40. data/commands/commands/rhoconnect/get_token.rb +25 -0
  41. data/commands/commands/rhoconnect/reset.rb +16 -0
  42. data/commands/commands/rhoconnect/reset_refresh.rb +11 -0
  43. data/commands/commands/rhoconnect/restart.rb +7 -0
  44. data/commands/commands/rhoconnect/secret.rb +11 -0
  45. data/commands/commands/rhoconnect/set_admin_password.rb +26 -0
  46. data/commands/commands/rhoconnect/spec.rb +15 -0
  47. data/commands/commands/rhoconnect/start.rb +18 -0
  48. data/commands/commands/rhoconnect/startbg.rb +34 -0
  49. data/commands/commands/rhoconnect/startdebug.rb +35 -0
  50. data/commands/commands/rhoconnect/stop.rb +11 -0
  51. data/commands/commands/rhoconnect/war.rb +32 -0
  52. data/commands/commands/rhoconnect/web.rb +7 -0
  53. data/commands/execute.rb +35 -0
  54. data/commands/generators/app.rb +6 -0
  55. data/commands/generators/source.rb +6 -0
  56. data/commands/utilities/dtach_installed.rb +10 -0
  57. data/doc/benchmarks-running.txt +5 -0
  58. data/doc/command-line.txt +216 -27
  59. data/doc/heroku-addon.txt +1 -1
  60. data/doc/preparing-production.txt +20 -1
  61. data/doc/public/cli.txt +191 -0
  62. data/doc/push-backend-setup.txt +148 -0
  63. data/doc/push-client-setup.txt +61 -0
  64. data/doc/push-server-setup.txt +91 -0
  65. data/doc/push.txt +8 -137
  66. data/doc/rest-api.txt +96 -0
  67. data/doc/settings.txt +1 -1
  68. data/doc/supported-platforms.txt +2 -1
  69. data/doc/tutorial.txt +6 -4
  70. data/examples/simple/Gemfile +39 -0
  71. data/examples/simple/Rakefile +7 -12
  72. data/examples/simple/config.ru +16 -31
  73. data/examples/simple/settings/settings.yml +5 -4
  74. data/examples/simple/sources/product.rb +51 -0
  75. data/generators/templates/application/Gemfile +7 -0
  76. data/generators/templates/application/Rakefile +5 -18
  77. data/generators/templates/application/config.ru +11 -19
  78. data/install.sh +24 -49
  79. data/installer/unix-like/create_texts.rb +71 -123
  80. data/installer/unix-like/post_install.sh +3 -0
  81. data/installer/unix-like/post_uninstall.sh +2 -0
  82. data/installer/unix-like/pre_install.sh +5 -3
  83. data/installer/unix-like/pre_uninstall.sh +14 -6
  84. data/installer/unix-like/rho_connect_install_checkers.rb +1 -1
  85. data/installer/unix-like/rho_connect_install_constants.rb +6 -10
  86. data/installer/unix-like/rho_connect_install_debian.rb +2 -2
  87. data/installer/unix-like/rho_connect_install_dnd.rb +2 -5
  88. data/installer/unix-like/rho_connect_install_installers.rb +15 -23
  89. data/installer/unix-like/rho_connect_install_yum.rb +2 -2
  90. data/installer/utils/constants.rb +4 -4
  91. data/installer/utils/create_sha1.rb +1 -1
  92. data/installer/utils/nix_install_test.rb +32 -31
  93. data/installer/utils/nix_installation.rake +1 -1
  94. data/installer/utils/package_upload/repos.rake +34 -30
  95. data/installer/utils/package_upload/s3_upload.rb +3 -3
  96. data/lib/rhoconnect/api/source/fast_delete.rb +10 -0
  97. data/lib/rhoconnect/api/source/fast_insert.rb +10 -0
  98. data/lib/rhoconnect/api/source/fast_update.rb +10 -0
  99. data/lib/rhoconnect/api/source/get_source_params.rb +1 -1
  100. data/lib/rhoconnect/api/source/list_sources.rb +2 -2
  101. data/lib/rhoconnect/api/source/save_adapter.rb +1 -1
  102. data/lib/rhoconnect/api/source/update_source_params.rb +6 -0
  103. data/lib/rhoconnect/async.rb +82 -0
  104. data/lib/rhoconnect/bulk_data/bulk_data.rb +5 -1
  105. data/lib/rhoconnect/client_sync.rb +18 -3
  106. data/lib/rhoconnect/console/rhoconnect_api.rb +2 -2
  107. data/lib/rhoconnect/console/server.rb +5 -32
  108. data/lib/rhoconnect/console.rb +2 -2
  109. data/lib/rhoconnect/graph_helper.rb +225 -0
  110. data/lib/rhoconnect/jobs/bulk_data_job.rb +24 -2
  111. data/lib/rhoconnect/server.rb +31 -11
  112. data/lib/rhoconnect/source.rb +10 -5
  113. data/lib/rhoconnect/source_sync.rb +32 -2
  114. data/lib/rhoconnect/tasks.rb +19 -108
  115. data/lib/rhoconnect/test_methods.rb +20 -0
  116. data/lib/rhoconnect/utilities.rb +118 -0
  117. data/lib/rhoconnect/version.rb +1 -1
  118. data/lib/rhoconnect/web-console/controllers/admins.js +245 -0
  119. data/lib/rhoconnect/web-console/models/adapter.js +53 -0
  120. data/lib/rhoconnect/web-console/models/client.js +105 -0
  121. data/lib/rhoconnect/web-console/models/doc.js +113 -0
  122. data/lib/rhoconnect/web-console/models/session.js +40 -0
  123. data/lib/rhoconnect/web-console/models/source.js +115 -0
  124. data/lib/rhoconnect/web-console/models/stats.js +84 -0
  125. data/lib/rhoconnect/web-console/models/user.js +111 -0
  126. data/lib/rhoconnect/web-console/public/backbone.js +1432 -0
  127. data/lib/rhoconnect/web-console/public/bootstrap.css +3990 -0
  128. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/excanvas.min.js +0 -0
  129. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.barRenderer.min.js +0 -0
  130. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.canvasAxisLabelRenderer.js +0 -0
  131. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.canvasAxisTickRenderer.js +0 -0
  132. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.canvasTextRenderer.js +0 -0
  133. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.categoryAxisRenderer.min.js +0 -0
  134. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.cursor.js +0 -0
  135. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.dateAxisRenderer.js +0 -0
  136. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.dateAxisRenderer.min.js +0 -0
  137. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jqplot.pointLabels.min.js +0 -0
  138. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jquery-1.4.2.min.js +0 -0
  139. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jquery.jqplot.min.css +0 -0
  140. data/lib/rhoconnect/{console/app → web-console}/public/jqplot/jquery.jqplot.min.js +0 -0
  141. data/lib/rhoconnect/web-console/public/jquery-1.7.1.min.js +154 -0
  142. data/lib/rhoconnect/web-console/public/rhoconnect-web.js +15 -0
  143. data/lib/rhoconnect/web-console/public/underscore.js +999 -0
  144. data/lib/rhoconnect/web-console/server.rb +55 -0
  145. data/lib/rhoconnect/web-console/templates/index.erb +90 -0
  146. data/lib/rhoconnect/web-console/templates/jqplot.erb +60 -0
  147. data/lib/rhoconnect/web-console/views/api_token.js +16 -0
  148. data/lib/rhoconnect/web-console/views/doc.js +63 -0
  149. data/lib/rhoconnect/web-console/views/edit_user.js +43 -0
  150. data/lib/rhoconnect/web-console/views/home.js +56 -0
  151. data/lib/rhoconnect/web-console/views/index.js +63 -0
  152. data/lib/rhoconnect/web-console/views/new_ping.js +58 -0
  153. data/lib/rhoconnect/web-console/views/new_user.js +29 -0
  154. data/lib/rhoconnect/web-console/views/server_doc.js +103 -0
  155. data/lib/rhoconnect/web-console/views/set_adapter.js +38 -0
  156. data/lib/rhoconnect/web-console/views/settings.js +53 -0
  157. data/lib/rhoconnect/web-console/views/show_device.js +56 -0
  158. data/lib/rhoconnect/web-console/views/show_user.js +38 -0
  159. data/lib/rhoconnect/web-console/views/source_docs.js +30 -0
  160. data/lib/rhoconnect/web-console/views/stats.js +69 -0
  161. data/lib/rhoconnect/web-console/views/users.js +20 -0
  162. data/lib/rhoconnect.rb +2 -1
  163. data/rhoconnect.gemspec +3 -1
  164. data/spec/api/application/rhoconnect_api_spec.rb +3 -5
  165. data/spec/api/source/fast_delete_spec.rb +27 -0
  166. data/spec/api/source/fast_insert_spec.rb +28 -0
  167. data/spec/api/source/fast_update_spec.rb +51 -0
  168. data/spec/api/source/get_source_params_spec.rb +1 -0
  169. data/spec/api/source/update_source_params_spec.rb +24 -0
  170. data/spec/async_spec.rb +19 -0
  171. data/spec/client_sync_spec.rb +19 -2
  172. data/spec/javascripts/PlayerSpec.js +58 -0
  173. data/spec/javascripts/admins_routes_spec.js +117 -0
  174. data/spec/javascripts/admins_spec.js +27 -0
  175. data/spec/javascripts/doc_view_spec.js +37 -0
  176. data/spec/javascripts/edit_user_view_spec.js +44 -0
  177. data/spec/javascripts/helpers/SpecHelper.js +9 -0
  178. data/spec/javascripts/helpers/jasmine-jquery.js +305 -0
  179. data/spec/javascripts/helpers/jasmine-sinon.js +43 -0
  180. data/spec/javascripts/helpers/sinon-1.3.2.js +3551 -0
  181. data/spec/javascripts/home_view_spec.js +39 -0
  182. data/spec/javascripts/index_view_spec.js +42 -0
  183. data/spec/javascripts/new_ping_view_spec.js +48 -0
  184. data/spec/javascripts/new_user_view_spec.js +42 -0
  185. data/spec/javascripts/server_doc_view_spec.js +39 -0
  186. data/spec/javascripts/set_adapter_view_spec.js +32 -0
  187. data/spec/javascripts/show_device_view_spec.js +41 -0
  188. data/spec/javascripts/show_user_view_spec.js +46 -0
  189. data/spec/javascripts/source_docs_view_spec.js +36 -0
  190. data/spec/javascripts/support/jasmine.yml +79 -0
  191. data/spec/javascripts/support/jasmine_config.rb +23 -0
  192. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  193. data/spec/javascripts/users_view_spec.js +35 -0
  194. data/spec/jobs/bulk_data_job_spec.rb +10 -2
  195. data/spec/perf/bulk_data_perf_spec.rb +1 -0
  196. data/spec/server/server_spec.rb +3 -1
  197. data/spec/source_sync_spec.rb +14 -1
  198. data/spec/spec_helper.rb +51 -0
  199. data/spec/store_spec.rb +6 -0
  200. data/spec/test_methods_spec.rb +11 -0
  201. data/tasks/redis.rake +3 -1
  202. metadata +172 -64
  203. data/doc/contributing.txt +0 -60
  204. data/lib/rhoconnect/console/app/helpers/auth_helper.rb +0 -22
  205. data/lib/rhoconnect/console/app/helpers/extensions.rb +0 -19
  206. data/lib/rhoconnect/console/app/helpers/helpers.rb +0 -57
  207. data/lib/rhoconnect/console/app/public/ThickBox.css +0 -649
  208. data/lib/rhoconnect/console/app/public/home.css +0 -431
  209. data/lib/rhoconnect/console/app/public/images/foot_logo_rhoconnect.png +0 -0
  210. data/lib/rhoconnect/console/app/public/images/header_halo.jpg +0 -0
  211. data/lib/rhoconnect/console/app/public/images/land_separator.gif +0 -0
  212. data/lib/rhoconnect/console/app/public/images/landing_header.jpg +0 -0
  213. data/lib/rhoconnect/console/app/public/images/logo_rhoconnect.png +0 -0
  214. data/lib/rhoconnect/console/app/public/images/tabs_separator.png +0 -0
  215. data/lib/rhoconnect/console/app/public/main.css +0 -7
  216. data/lib/rhoconnect/console/app/public/reset.css +0 -76
  217. data/lib/rhoconnect/console/app/public/style.css +0 -2201
  218. data/lib/rhoconnect/console/app/public/text.txt +0 -0
  219. data/lib/rhoconnect/console/app/routes/adapter.rb +0 -28
  220. data/lib/rhoconnect/console/app/routes/auth.rb +0 -29
  221. data/lib/rhoconnect/console/app/routes/client.rb +0 -31
  222. data/lib/rhoconnect/console/app/routes/docs.rb +0 -145
  223. data/lib/rhoconnect/console/app/routes/heroku.rb +0 -19
  224. data/lib/rhoconnect/console/app/routes/home.rb +0 -63
  225. data/lib/rhoconnect/console/app/routes/timing.rb +0 -242
  226. data/lib/rhoconnect/console/app/routes/user.rb +0 -122
  227. data/lib/rhoconnect/console/app/views/adapter.erb +0 -16
  228. data/lib/rhoconnect/console/app/views/client.erb +0 -30
  229. data/lib/rhoconnect/console/app/views/content.erb +0 -14
  230. data/lib/rhoconnect/console/app/views/doc.erb +0 -8
  231. data/lib/rhoconnect/console/app/views/docdata.erb +0 -28
  232. data/lib/rhoconnect/console/app/views/docs.erb +0 -30
  233. data/lib/rhoconnect/console/app/views/edituser.erb +0 -13
  234. data/lib/rhoconnect/console/app/views/headermenu.erb +0 -40
  235. data/lib/rhoconnect/console/app/views/home.erb +0 -24
  236. data/lib/rhoconnect/console/app/views/index.erb +0 -58
  237. data/lib/rhoconnect/console/app/views/jqplot.erb +0 -52
  238. data/lib/rhoconnect/console/app/views/layout.erb +0 -153
  239. data/lib/rhoconnect/console/app/views/login.erb +0 -26
  240. data/lib/rhoconnect/console/app/views/newuser.erb +0 -17
  241. data/lib/rhoconnect/console/app/views/ping.erb +0 -40
  242. data/lib/rhoconnect/console/app/views/result.erb +0 -11
  243. data/lib/rhoconnect/console/app/views/rightboxlinks.erb +0 -15
  244. data/lib/rhoconnect/console/app/views/select_doc.erb +0 -17
  245. data/lib/rhoconnect/console/app/views/upload_doc.erb +0 -23
  246. data/lib/rhoconnect/console/app/views/user.erb +0 -29
  247. data/lib/rhoconnect/console/app/views/users.erb +0 -19
  248. data/lib/rhoconnect/server/views/index.erb +0 -13
@@ -0,0 +1,3551 @@
1
+ /**
2
+ * Sinon.JS 1.3.2, 2012/03/11
3
+ *
4
+ * @author Christian Johansen (christian@cjohansen.no)
5
+ *
6
+ * (The BSD License)
7
+ *
8
+ * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
9
+ * All rights reserved.
10
+ *
11
+ * Redistribution and use in source and binary forms, with or without modification,
12
+ * are permitted provided that the following conditions are met:
13
+ *
14
+ * * Redistributions of source code must retain the above copyright notice,
15
+ * this list of conditions and the following disclaimer.
16
+ * * Redistributions in binary form must reproduce the above copyright notice,
17
+ * this list of conditions and the following disclaimer in the documentation
18
+ * and/or other materials provided with the distribution.
19
+ * * Neither the name of Christian Johansen nor the names of his contributors
20
+ * may be used to endorse or promote products derived from this software
21
+ * without specific prior written permission.
22
+ *
23
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+ */
34
+
35
+ "use strict";
36
+ var sinon = (function () {
37
+ var buster = (function (buster, setTimeout) {
38
+ function extend(target) {
39
+ if (!target) {
40
+ return;
41
+ }
42
+
43
+ for (var i = 1, l = arguments.length, prop; i < l; ++i) {
44
+ for (prop in arguments[i]) {
45
+ target[prop] = arguments[i][prop];
46
+ }
47
+ }
48
+
49
+ return target;
50
+ }
51
+
52
+ var div = typeof document != "undefined" && document.createElement("div");
53
+
54
+ return extend(buster, {
55
+ bind: function (obj, methOrProp) {
56
+ var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp;
57
+ var args = Array.prototype.slice.call(arguments, 2);
58
+
59
+ return function () {
60
+ var allArgs = args.concat(Array.prototype.slice.call(arguments));
61
+ return method.apply(obj, allArgs);
62
+ };
63
+ },
64
+
65
+ create: (function () {
66
+ function F() {}
67
+
68
+ return function create(object) {
69
+ F.prototype = object;
70
+ return new F();
71
+ }
72
+ }()),
73
+
74
+ extend: extend,
75
+
76
+ nextTick: function (callback) {
77
+ if (typeof process != "undefined" && process.nextTick) {
78
+ return process.nextTick(callback);
79
+ }
80
+
81
+ setTimeout(callback, 0);
82
+ },
83
+
84
+ functionName: function (func) {
85
+ if (!func) return "";
86
+ if (func.displayName) return func.displayName;
87
+ if (func.name) return func.name;
88
+
89
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
90
+ return matches && matches[1] || "";
91
+ },
92
+
93
+ isNode: function (obj) {
94
+ if (!div) return false;
95
+
96
+ try {
97
+ obj.appendChild(div);
98
+ obj.removeChild(div);
99
+ } catch (e) {
100
+ return false;
101
+ }
102
+
103
+ return true;
104
+ },
105
+
106
+ isElement: function (obj) {
107
+ return obj && buster.isNode(obj) && obj.nodeType === 1;
108
+ }
109
+ });
110
+ }(buster || {}, setTimeout));
111
+
112
+ if (typeof module == "object" && typeof require == "function") {
113
+ module.exports = buster;
114
+ buster.eventEmitter = require("./buster-event-emitter");
115
+
116
+ Object.defineProperty(buster, "defineVersionGetter", {
117
+ get: function () {
118
+ return require("./define-version-getter");
119
+ }
120
+ });
121
+ }
122
+
123
+
124
+ if (typeof require != "undefined") {
125
+ buster = require("buster-core");
126
+ }
127
+
128
+ buster.format = buster.format || {};
129
+ buster.format.excludeConstructors = ["Object", /^.$/];
130
+ buster.format.quoteStrings = true;
131
+
132
+ buster.format.ascii = (function () {
133
+ function keys(object) {
134
+ var k = Object.keys && Object.keys(object) || [];
135
+
136
+ if (k.length == 0) {
137
+ for (var prop in object) {
138
+ if (object.hasOwnProperty(prop)) {
139
+ k.push(prop);
140
+ }
141
+ }
142
+ }
143
+
144
+ return k.sort();
145
+ }
146
+
147
+ function isCircular(object, objects) {
148
+ if (typeof object != "object") {
149
+ return false;
150
+ }
151
+
152
+ for (var i = 0, l = objects.length; i < l; ++i) {
153
+ if (objects[i] === object) {
154
+ return true;
155
+ }
156
+ }
157
+
158
+ return false;
159
+ }
160
+
161
+ function ascii(object, processed, indent) {
162
+ if (typeof object == "string") {
163
+ var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings;
164
+ return processed || quote ? '"' + object + '"' : object;
165
+ }
166
+
167
+ if (typeof object == "function" && !(object instanceof RegExp)) {
168
+ return ascii.func(object);
169
+ }
170
+
171
+ processed = processed || [];
172
+
173
+ if (isCircular(object, processed)) {
174
+ return "[Circular]";
175
+ }
176
+
177
+ if (Object.prototype.toString.call(object) == "[object Array]") {
178
+ return ascii.array(object);
179
+ }
180
+
181
+ if (!object) {
182
+ return "" + object;
183
+ }
184
+
185
+ if (buster.isElement(object)) {
186
+ return ascii.element(object);
187
+ }
188
+
189
+ if (object.toString !== Object.prototype.toString) {
190
+ return object.toString();
191
+ }
192
+
193
+ return ascii.object.call(this, object, processed, indent);
194
+ }
195
+
196
+ ascii.func = function (func) {
197
+ return "function " + buster.functionName(func) + "() {}";
198
+ };
199
+
200
+ ascii.array = function (array, processed) {
201
+ processed = processed || [];
202
+ processed.push(array);
203
+ var pieces = [];
204
+
205
+ for (var i = 0, l = array.length; i < l; ++i) {
206
+ pieces.push(ascii(array[i], processed));
207
+ }
208
+
209
+ return "[" + pieces.join(", ") + "]";
210
+ };
211
+
212
+ ascii.object = function (object, processed, indent) {
213
+ processed = processed || [];
214
+ processed.push(object);
215
+ indent = indent || 0;
216
+ var pieces = [], properties = keys(object), prop, str, obj;
217
+ var is = "";
218
+ var length = 3;
219
+
220
+ for (var i = 0, l = indent; i < l; ++i) {
221
+ is += " ";
222
+ }
223
+
224
+ for (i = 0, l = properties.length; i < l; ++i) {
225
+ prop = properties[i];
226
+ obj = object[prop];
227
+
228
+ if (isCircular(obj, processed)) {
229
+ str = "[Circular]";
230
+ } else {
231
+ str = ascii.call(this, obj, processed, indent + 2);
232
+ }
233
+
234
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
235
+ length += str.length;
236
+ pieces.push(str);
237
+ }
238
+
239
+ var cons = ascii.constructorName.call(this, object);
240
+ var prefix = cons ? "[" + cons + "] " : ""
241
+
242
+ return (length + indent) > 80 ?
243
+ prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" :
244
+ prefix + "{ " + pieces.join(", ") + " }";
245
+ };
246
+
247
+ ascii.element = function (element) {
248
+ var tagName = element.tagName.toLowerCase();
249
+ var attrs = element.attributes, attribute, pairs = [], attrName;
250
+
251
+ for (var i = 0, l = attrs.length; i < l; ++i) {
252
+ attribute = attrs.item(i);
253
+ attrName = attribute.nodeName.toLowerCase().replace("html:", "");
254
+
255
+ if (attrName == "contenteditable" && attribute.nodeValue == "inherit") {
256
+ continue;
257
+ }
258
+
259
+ if (!!attribute.nodeValue) {
260
+ pairs.push(attrName + "=\"" + attribute.nodeValue + "\"");
261
+ }
262
+ }
263
+
264
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
265
+ var content = element.innerHTML;
266
+
267
+ if (content.length > 20) {
268
+ content = content.substr(0, 20) + "[...]";
269
+ }
270
+
271
+ var res = formatted + pairs.join(" ") + ">" + content + "</" + tagName + ">";
272
+
273
+ return res.replace(/ contentEditable="inherit"/, "");
274
+ };
275
+
276
+ ascii.constructorName = function (object) {
277
+ var name = buster.functionName(object && object.constructor);
278
+ var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];
279
+
280
+ for (var i = 0, l = excludes.length; i < l; ++i) {
281
+ if (typeof excludes[i] == "string" && excludes[i] == name) {
282
+ return "";
283
+ } else if (excludes[i].test && excludes[i].test(name)) {
284
+ return "";
285
+ }
286
+ }
287
+
288
+ return name;
289
+ };
290
+
291
+ return ascii;
292
+ }());
293
+
294
+ if (typeof module != "undefined") {
295
+ module.exports = buster.format;
296
+ }
297
+ /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
298
+ /*global module, require, __dirname, document*/
299
+ /**
300
+ * Sinon core utilities. For internal use only.
301
+ *
302
+ * @author Christian Johansen (christian@cjohansen.no)
303
+ * @license BSD
304
+ *
305
+ * Copyright (c) 2010-2011 Christian Johansen
306
+ */
307
+
308
+ var sinon = (function (buster) {
309
+ var div = typeof document != "undefined" && document.createElement("div");
310
+ var hasOwn = Object.prototype.hasOwnProperty;
311
+
312
+ function isDOMNode(obj) {
313
+ var success = false;
314
+
315
+ try {
316
+ obj.appendChild(div);
317
+ success = div.parentNode == obj;
318
+ } catch (e) {
319
+ return false;
320
+ } finally {
321
+ try {
322
+ obj.removeChild(div);
323
+ } catch (e) {
324
+ // Remove failed, not much we can do about that
325
+ }
326
+ }
327
+
328
+ return success;
329
+ }
330
+
331
+ function isElement(obj) {
332
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
333
+ }
334
+
335
+ function isFunction(obj) {
336
+ return !!(obj && obj.constructor && obj.call && obj.apply);
337
+ }
338
+
339
+ function mirrorProperties(target, source) {
340
+ for (var prop in source) {
341
+ if (!hasOwn.call(target, prop)) {
342
+ target[prop] = source[prop];
343
+ }
344
+ }
345
+ }
346
+
347
+ var sinon = {
348
+ wrapMethod: function wrapMethod(object, property, method) {
349
+ if (!object) {
350
+ throw new TypeError("Should wrap property of object");
351
+ }
352
+
353
+ if (typeof method != "function") {
354
+ throw new TypeError("Method wrapper should be function");
355
+ }
356
+
357
+ var wrappedMethod = object[property];
358
+
359
+ if (!isFunction(wrappedMethod)) {
360
+ throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
361
+ property + " as function");
362
+ }
363
+
364
+ if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
365
+ throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
366
+ }
367
+
368
+ if (wrappedMethod.calledBefore) {
369
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
370
+ throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
371
+ }
372
+
373
+ // IE 8 does not support hasOwnProperty on the window object.
374
+ var owned = hasOwn.call(object, property);
375
+ object[property] = method;
376
+ method.displayName = property;
377
+
378
+ method.restore = function () {
379
+ if(owned) {
380
+ object[property] = wrappedMethod;
381
+ } else {
382
+ delete object[property];
383
+ }
384
+ };
385
+
386
+ method.restore.sinon = true;
387
+ mirrorProperties(method, wrappedMethod);
388
+
389
+ return method;
390
+ },
391
+
392
+ extend: function extend(target) {
393
+ for (var i = 1, l = arguments.length; i < l; i += 1) {
394
+ for (var prop in arguments[i]) {
395
+ if (arguments[i].hasOwnProperty(prop)) {
396
+ target[prop] = arguments[i][prop];
397
+ }
398
+
399
+ // DONT ENUM bug, only care about toString
400
+ if (arguments[i].hasOwnProperty("toString") &&
401
+ arguments[i].toString != target.toString) {
402
+ target.toString = arguments[i].toString;
403
+ }
404
+ }
405
+ }
406
+
407
+ return target;
408
+ },
409
+
410
+ create: function create(proto) {
411
+ var F = function () {};
412
+ F.prototype = proto;
413
+ return new F();
414
+ },
415
+
416
+ deepEqual: function deepEqual(a, b) {
417
+ if (typeof a != "object" || typeof b != "object") {
418
+ return a === b;
419
+ }
420
+
421
+ if (isElement(a) || isElement(b)) {
422
+ return a === b;
423
+ }
424
+
425
+ if (a === b) {
426
+ return true;
427
+ }
428
+
429
+ var aString = Object.prototype.toString.call(a);
430
+ if (aString != Object.prototype.toString.call(b)) {
431
+ return false;
432
+ }
433
+
434
+ if (aString == "[object Array]") {
435
+ if (a.length !== b.length) {
436
+ return false;
437
+ }
438
+
439
+ for (var i = 0, l = a.length; i < l; i += 1) {
440
+ if (!deepEqual(a[i], b[i])) {
441
+ return false;
442
+ }
443
+ }
444
+
445
+ return true;
446
+ }
447
+
448
+ var prop, aLength = 0, bLength = 0;
449
+
450
+ for (prop in a) {
451
+ aLength += 1;
452
+
453
+ if (!deepEqual(a[prop], b[prop])) {
454
+ return false;
455
+ }
456
+ }
457
+
458
+ for (prop in b) {
459
+ bLength += 1;
460
+ }
461
+
462
+ if (aLength != bLength) {
463
+ return false;
464
+ }
465
+
466
+ return true;
467
+ },
468
+
469
+ functionName: function functionName(func) {
470
+ var name = func.displayName || func.name;
471
+
472
+ // Use function decomposition as a last resort to get function
473
+ // name. Does not rely on function decomposition to work - if it
474
+ // doesn't debugging will be slightly less informative
475
+ // (i.e. toString will say 'spy' rather than 'myFunc').
476
+ if (!name) {
477
+ var matches = func.toString().match(/function ([^\s\(]+)/);
478
+ name = matches && matches[1];
479
+ }
480
+
481
+ return name;
482
+ },
483
+
484
+ functionToString: function toString() {
485
+ if (this.getCall && this.callCount) {
486
+ var thisValue, prop, i = this.callCount;
487
+
488
+ while (i--) {
489
+ thisValue = this.getCall(i).thisValue;
490
+
491
+ for (prop in thisValue) {
492
+ if (thisValue[prop] === this) {
493
+ return prop;
494
+ }
495
+ }
496
+ }
497
+ }
498
+
499
+ return this.displayName || "sinon fake";
500
+ },
501
+
502
+ getConfig: function (custom) {
503
+ var config = {};
504
+ custom = custom || {};
505
+ var defaults = sinon.defaultConfig;
506
+
507
+ for (var prop in defaults) {
508
+ if (defaults.hasOwnProperty(prop)) {
509
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
510
+ }
511
+ }
512
+
513
+ return config;
514
+ },
515
+
516
+ format: function (val) {
517
+ return "" + val;
518
+ },
519
+
520
+ defaultConfig: {
521
+ injectIntoThis: true,
522
+ injectInto: null,
523
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
524
+ useFakeTimers: true,
525
+ useFakeServer: true
526
+ },
527
+
528
+ timesInWords: function timesInWords(count) {
529
+ return count == 1 && "once" ||
530
+ count == 2 && "twice" ||
531
+ count == 3 && "thrice" ||
532
+ (count || 0) + " times";
533
+ },
534
+
535
+ calledInOrder: function (spies) {
536
+ for (var i = 1, l = spies.length; i < l; i++) {
537
+ if (!spies[i - 1].calledBefore(spies[i])) {
538
+ return false;
539
+ }
540
+ }
541
+
542
+ return true;
543
+ },
544
+
545
+ orderByFirstCall: function (spies) {
546
+ return spies.sort(function (a, b) {
547
+ // uuid, won't ever be equal
548
+ var aCall = a.getCall(0);
549
+ var bCall = b.getCall(0);
550
+ var aId = aCall && aCall.callId || -1;
551
+ var bId = bCall && bCall.callId || -1;
552
+
553
+ return aId < bId ? -1 : 1;
554
+ });
555
+ },
556
+
557
+ log: function () {},
558
+
559
+ logError: function (label, err) {
560
+ var msg = label + " threw exception: "
561
+ sinon.log(msg + "[" + err.name + "] " + err.message);
562
+ if (err.stack) { sinon.log(err.stack); }
563
+
564
+ setTimeout(function () {
565
+ err.message = msg + err.message;
566
+ throw err;
567
+ }, 0);
568
+ }
569
+ };
570
+
571
+ var isNode = typeof module == "object" && typeof require == "function";
572
+
573
+ if (isNode) {
574
+ try {
575
+ buster = { format: require("buster-format") };
576
+ } catch (e) {}
577
+ module.exports = sinon;
578
+ module.exports.spy = require("./sinon/spy");
579
+ module.exports.stub = require("./sinon/stub");
580
+ module.exports.mock = require("./sinon/mock");
581
+ module.exports.collection = require("./sinon/collection");
582
+ module.exports.assert = require("./sinon/assert");
583
+ module.exports.sandbox = require("./sinon/sandbox");
584
+ module.exports.test = require("./sinon/test");
585
+ module.exports.testCase = require("./sinon/test_case");
586
+ module.exports.assert = require("./sinon/assert");
587
+ }
588
+
589
+ if (buster) {
590
+ var formatter = sinon.create(buster.format);
591
+ formatter.quoteStrings = false;
592
+ sinon.format = function () {
593
+ return formatter.ascii.apply(formatter, arguments);
594
+ };
595
+ } else if (isNode) {
596
+ try {
597
+ var util = require("util");
598
+ sinon.format = function (value) {
599
+ return typeof value == "object" ? util.inspect(value) : value;
600
+ };
601
+ } catch (e) {
602
+ /* Node, but no util module - would be very old, but better safe than
603
+ sorry */
604
+ }
605
+ }
606
+
607
+ return sinon;
608
+ }(typeof buster == "object" && buster));
609
+
610
+ /* @depend ../sinon.js */
611
+ /*jslint eqeqeq: false, onevar: false, plusplus: false*/
612
+ /*global module, require, sinon*/
613
+ /**
614
+ * Spy functions
615
+ *
616
+ * @author Christian Johansen (christian@cjohansen.no)
617
+ * @license BSD
618
+ *
619
+ * Copyright (c) 2010-2011 Christian Johansen
620
+ */
621
+
622
+ (function (sinon) {
623
+ var commonJSModule = typeof module == "object" && typeof require == "function";
624
+ var spyCall;
625
+ var callId = 0;
626
+ var push = [].push;
627
+ var slice = Array.prototype.slice;
628
+
629
+ if (!sinon && commonJSModule) {
630
+ sinon = require("../sinon");
631
+ }
632
+
633
+ if (!sinon) {
634
+ return;
635
+ }
636
+
637
+ function spy(object, property) {
638
+ if (!property && typeof object == "function") {
639
+ return spy.create(object);
640
+ }
641
+
642
+ if (!object || !property) {
643
+ return spy.create(function () {});
644
+ }
645
+
646
+ var method = object[property];
647
+ return sinon.wrapMethod(object, property, spy.create(method));
648
+ }
649
+
650
+ sinon.extend(spy, (function () {
651
+
652
+ function delegateToCalls(api, method, matchAny, actual, notCalled) {
653
+ api[method] = function () {
654
+ if (!this.called) {
655
+ if (notCalled) {
656
+ return notCalled.apply(this, arguments);
657
+ }
658
+ return false;
659
+ }
660
+
661
+ var currentCall;
662
+ var matches = 0;
663
+
664
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
665
+ currentCall = this.getCall(i);
666
+
667
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
668
+ matches += 1;
669
+
670
+ if (matchAny) {
671
+ return true;
672
+ }
673
+ }
674
+ }
675
+
676
+ return matches === this.callCount;
677
+ };
678
+ }
679
+
680
+ function matchingFake(fakes, args, strict) {
681
+ if (!fakes) {
682
+ return;
683
+ }
684
+
685
+ var alen = args.length;
686
+
687
+ for (var i = 0, l = fakes.length; i < l; i++) {
688
+ if (fakes[i].matches(args, strict)) {
689
+ return fakes[i];
690
+ }
691
+ }
692
+ }
693
+
694
+ function incrementCallCount() {
695
+ this.called = true;
696
+ this.callCount += 1;
697
+ this.calledOnce = this.callCount == 1;
698
+ this.calledTwice = this.callCount == 2;
699
+ this.calledThrice = this.callCount == 3;
700
+ }
701
+
702
+ function createCallProperties() {
703
+ this.firstCall = this.getCall(0);
704
+ this.secondCall = this.getCall(1);
705
+ this.thirdCall = this.getCall(2);
706
+ this.lastCall = this.getCall(this.callCount - 1);
707
+ }
708
+
709
+ var uuid = 0;
710
+
711
+ // Public API
712
+ var spyApi = {
713
+ reset: function () {
714
+ this.called = false;
715
+ this.calledOnce = false;
716
+ this.calledTwice = false;
717
+ this.calledThrice = false;
718
+ this.callCount = 0;
719
+ this.firstCall = null;
720
+ this.secondCall = null;
721
+ this.thirdCall = null;
722
+ this.lastCall = null;
723
+ this.args = [];
724
+ this.returnValues = [];
725
+ this.thisValues = [];
726
+ this.exceptions = [];
727
+ this.callIds = [];
728
+ },
729
+
730
+ create: function create(func) {
731
+ var name;
732
+
733
+ if (typeof func != "function") {
734
+ func = function () {};
735
+ } else {
736
+ name = sinon.functionName(func);
737
+ }
738
+
739
+ function proxy() {
740
+ return proxy.invoke(func, this, slice.call(arguments));
741
+ }
742
+
743
+ sinon.extend(proxy, spy);
744
+ delete proxy.create;
745
+ sinon.extend(proxy, func);
746
+
747
+ proxy.reset();
748
+ proxy.prototype = func.prototype;
749
+ proxy.displayName = name || "spy";
750
+ proxy.toString = sinon.functionToString;
751
+ proxy._create = sinon.spy.create;
752
+ proxy.id = "spy#" + uuid++;
753
+
754
+ return proxy;
755
+ },
756
+
757
+ invoke: function invoke(func, thisValue, args) {
758
+ var matching = matchingFake(this.fakes, args);
759
+ var exception, returnValue;
760
+
761
+ incrementCallCount.call(this);
762
+ push.call(this.thisValues, thisValue);
763
+ push.call(this.args, args);
764
+ push.call(this.callIds, callId++);
765
+
766
+ try {
767
+ if (matching) {
768
+ returnValue = matching.invoke(func, thisValue, args);
769
+ } else {
770
+ returnValue = (this.func || func).apply(thisValue, args);
771
+ }
772
+ } catch (e) {
773
+ push.call(this.returnValues, undefined);
774
+ exception = e;
775
+ throw e;
776
+ } finally {
777
+ push.call(this.exceptions, exception);
778
+ }
779
+
780
+ push.call(this.returnValues, returnValue);
781
+
782
+ createCallProperties.call(this);
783
+
784
+ return returnValue;
785
+ },
786
+
787
+ getCall: function getCall(i) {
788
+ if (i < 0 || i >= this.callCount) {
789
+ return null;
790
+ }
791
+
792
+ return spyCall.create(this, this.thisValues[i], this.args[i],
793
+ this.returnValues[i], this.exceptions[i],
794
+ this.callIds[i]);
795
+ },
796
+
797
+ calledBefore: function calledBefore(spyFn) {
798
+ if (!this.called) {
799
+ return false;
800
+ }
801
+
802
+ if (!spyFn.called) {
803
+ return true;
804
+ }
805
+
806
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
807
+ },
808
+
809
+ calledAfter: function calledAfter(spyFn) {
810
+ if (!this.called || !spyFn.called) {
811
+ return false;
812
+ }
813
+
814
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
815
+ },
816
+
817
+ withArgs: function () {
818
+ var args = slice.call(arguments);
819
+
820
+ if (this.fakes) {
821
+ var match = matchingFake(this.fakes, args, true);
822
+
823
+ if (match) {
824
+ return match;
825
+ }
826
+ } else {
827
+ this.fakes = [];
828
+ }
829
+
830
+ var original = this;
831
+ var fake = this._create();
832
+ fake.matchingAguments = args;
833
+ push.call(this.fakes, fake);
834
+
835
+ fake.withArgs = function () {
836
+ return original.withArgs.apply(original, arguments);
837
+ };
838
+
839
+ for (var i = 0; i < this.args.length; i++) {
840
+ if (fake.matches(this.args[i])) {
841
+ incrementCallCount.call(fake);
842
+ push.call(fake.thisValues, this.thisValues[i]);
843
+ push.call(fake.args, this.args[i]);
844
+ push.call(fake.returnValues, this.returnValues[i]);
845
+ push.call(fake.exceptions, this.exceptions[i]);
846
+ push.call(fake.callIds, this.callIds[i]);
847
+ }
848
+ }
849
+ createCallProperties.call(fake);
850
+
851
+ return fake;
852
+ },
853
+
854
+ matches: function (args, strict) {
855
+ var margs = this.matchingAguments;
856
+
857
+ if (margs.length <= args.length &&
858
+ sinon.deepEqual(margs, args.slice(0, margs.length))) {
859
+ return !strict || margs.length == args.length;
860
+ }
861
+ },
862
+
863
+ printf: function (format) {
864
+ var spy = this;
865
+ var args = slice.call(arguments, 1);
866
+ var formatter;
867
+
868
+ return (format || "").replace(/%(.)/g, function (match, specifyer) {
869
+ formatter = spyApi.formatters[specifyer];
870
+
871
+ if (typeof formatter == "function") {
872
+ return formatter.call(null, spy, args);
873
+ } else if (!isNaN(parseInt(specifyer), 10)) {
874
+ return sinon.format(args[specifyer - 1]);
875
+ }
876
+
877
+ return "%" + specifyer;
878
+ });
879
+ }
880
+ };
881
+
882
+ delegateToCalls(spyApi, "calledOn", true);
883
+ delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn");
884
+ delegateToCalls(spyApi, "calledWith", true);
885
+ delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith");
886
+ delegateToCalls(spyApi, "calledWithExactly", true);
887
+ delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly");
888
+ delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith",
889
+ function () { return true; });
890
+ delegateToCalls(spyApi, "threw", true);
891
+ delegateToCalls(spyApi, "alwaysThrew", false, "threw");
892
+ delegateToCalls(spyApi, "returned", true);
893
+ delegateToCalls(spyApi, "alwaysReturned", false, "returned");
894
+ delegateToCalls(spyApi, "calledWithNew", true);
895
+ delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew");
896
+ delegateToCalls(spyApi, "callArg", false, "callArgWith", function () {
897
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
898
+ });
899
+ spyApi.callArgWith = spyApi.callArg;
900
+ delegateToCalls(spyApi, "yield", false, "yield", function () {
901
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
902
+ });
903
+ // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
904
+ spyApi.invokeCallback = spyApi.yield;
905
+ delegateToCalls(spyApi, "yieldTo", false, "yieldTo", function (property) {
906
+ throw new Error(this.toString() + " cannot yield to '" + property +
907
+ "' since it was not yet invoked.");
908
+ });
909
+
910
+ spyApi.formatters = {
911
+ "c": function (spy) {
912
+ return sinon.timesInWords(spy.callCount);
913
+ },
914
+
915
+ "n": function (spy) {
916
+ return spy.toString();
917
+ },
918
+
919
+ "C": function (spy) {
920
+ var calls = [];
921
+
922
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
923
+ push.call(calls, " " + spy.getCall(i).toString());
924
+ }
925
+
926
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
927
+ },
928
+
929
+ "t": function (spy) {
930
+ var objects = [];
931
+
932
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
933
+ push.call(objects, sinon.format(spy.thisValues[i]));
934
+ }
935
+
936
+ return objects.join(", ");
937
+ },
938
+
939
+ "*": function (spy, args) {
940
+ return args.join(", ");
941
+ }
942
+ };
943
+
944
+ return spyApi;
945
+ }()));
946
+
947
+ spyCall = (function () {
948
+
949
+ function throwYieldError(proxy, text, args) {
950
+ var msg = sinon.functionName(proxy) + text;
951
+ if (args.length) {
952
+ msg += " Received [" + slice.call(args).join(", ") + "]";
953
+ }
954
+ throw new Error(msg);
955
+ }
956
+
957
+ return {
958
+ create: function create(spy, thisValue, args, returnValue, exception, id) {
959
+ var proxyCall = sinon.create(spyCall);
960
+ delete proxyCall.create;
961
+ proxyCall.proxy = spy;
962
+ proxyCall.thisValue = thisValue;
963
+ proxyCall.args = args;
964
+ proxyCall.returnValue = returnValue;
965
+ proxyCall.exception = exception;
966
+ proxyCall.callId = typeof id == "number" && id || callId++;
967
+
968
+ return proxyCall;
969
+ },
970
+
971
+ calledOn: function calledOn(thisValue) {
972
+ return this.thisValue === thisValue;
973
+ },
974
+
975
+ calledWith: function calledWith() {
976
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
977
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
978
+ return false;
979
+ }
980
+ }
981
+
982
+ return true;
983
+ },
984
+
985
+ calledWithExactly: function calledWithExactly() {
986
+ return arguments.length == this.args.length &&
987
+ this.calledWith.apply(this, arguments);
988
+ },
989
+
990
+ notCalledWith: function notCalledWith() {
991
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
992
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
993
+ return true;
994
+ }
995
+ }
996
+ return false;
997
+ },
998
+
999
+ returned: function returned(value) {
1000
+ return this.returnValue === value;
1001
+ },
1002
+
1003
+ threw: function threw(error) {
1004
+ if (typeof error == "undefined" || !this.exception) {
1005
+ return !!this.exception;
1006
+ }
1007
+
1008
+ if (typeof error == "string") {
1009
+ return this.exception.name == error;
1010
+ }
1011
+
1012
+ return this.exception === error;
1013
+ },
1014
+
1015
+ calledWithNew: function calledWithNew(thisValue) {
1016
+ return this.thisValue instanceof this.proxy;
1017
+ },
1018
+
1019
+ calledBefore: function (other) {
1020
+ return this.callId < other.callId;
1021
+ },
1022
+
1023
+ calledAfter: function (other) {
1024
+ return this.callId > other.callId;
1025
+ },
1026
+
1027
+ callArg: function (pos) {
1028
+ this.args[pos]();
1029
+ },
1030
+
1031
+ callArgWith: function (pos) {
1032
+ var args = slice.call(arguments, 1);
1033
+ this.args[pos].apply(null, args);
1034
+ },
1035
+
1036
+ "yield": function () {
1037
+ var args = this.args;
1038
+ for (var i = 0, l = args.length; i < l; ++i) {
1039
+ if (typeof args[i] === "function") {
1040
+ args[i].apply(null, slice.call(arguments));
1041
+ return;
1042
+ }
1043
+ }
1044
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
1045
+ },
1046
+
1047
+ yieldTo: function (prop) {
1048
+ var args = this.args;
1049
+ for (var i = 0, l = args.length; i < l; ++i) {
1050
+ if (args[i] && typeof args[i][prop] === "function") {
1051
+ args[i][prop].apply(null, slice.call(arguments, 1));
1052
+ return;
1053
+ }
1054
+ }
1055
+ throwYieldError(this.proxy, " cannot yield to '" + prop +
1056
+ "' since no callback was passed.", args);
1057
+ },
1058
+
1059
+ toString: function () {
1060
+ var callStr = this.proxy.toString() + "(";
1061
+ var args = [];
1062
+
1063
+ for (var i = 0, l = this.args.length; i < l; ++i) {
1064
+ push.call(args, sinon.format(this.args[i]));
1065
+ }
1066
+
1067
+ callStr = callStr + args.join(", ") + ")";
1068
+
1069
+ if (typeof this.returnValue != "undefined") {
1070
+ callStr += " => " + sinon.format(this.returnValue);
1071
+ }
1072
+
1073
+ if (this.exception) {
1074
+ callStr += " !" + this.exception.name;
1075
+
1076
+ if (this.exception.message) {
1077
+ callStr += "(" + this.exception.message + ")";
1078
+ }
1079
+ }
1080
+
1081
+ return callStr;
1082
+ }
1083
+ };
1084
+ }());
1085
+
1086
+ spy.spyCall = spyCall;
1087
+
1088
+ // This steps outside the module sandbox and will be removed
1089
+ sinon.spyCall = spyCall;
1090
+
1091
+ if (commonJSModule) {
1092
+ module.exports = spy;
1093
+ } else {
1094
+ sinon.spy = spy;
1095
+ }
1096
+ }(typeof sinon == "object" && sinon || null));
1097
+
1098
+ /**
1099
+ * @depend ../sinon.js
1100
+ * @depend spy.js
1101
+ */
1102
+ /*jslint eqeqeq: false, onevar: false*/
1103
+ /*global module, require, sinon*/
1104
+ /**
1105
+ * Stub functions
1106
+ *
1107
+ * @author Christian Johansen (christian@cjohansen.no)
1108
+ * @license BSD
1109
+ *
1110
+ * Copyright (c) 2010-2011 Christian Johansen
1111
+ */
1112
+
1113
+ (function (sinon) {
1114
+ var commonJSModule = typeof module == "object" && typeof require == "function";
1115
+
1116
+ if (!sinon && commonJSModule) {
1117
+ sinon = require("../sinon");
1118
+ }
1119
+
1120
+ if (!sinon) {
1121
+ return;
1122
+ }
1123
+
1124
+ function stub(object, property, func) {
1125
+ if (!!func && typeof func != "function") {
1126
+ throw new TypeError("Custom stub should be function");
1127
+ }
1128
+
1129
+ var wrapper;
1130
+
1131
+ if (func) {
1132
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
1133
+ } else {
1134
+ wrapper = stub.create();
1135
+ }
1136
+
1137
+ if (!object && !property) {
1138
+ return sinon.stub.create();
1139
+ }
1140
+
1141
+ if (!property && !!object && typeof object == "object") {
1142
+ for (var prop in object) {
1143
+ if (typeof object[prop] === "function") {
1144
+ stub(object, prop);
1145
+ }
1146
+ }
1147
+
1148
+ return object;
1149
+ }
1150
+
1151
+ return sinon.wrapMethod(object, property, wrapper);
1152
+ }
1153
+
1154
+ function getCallback(stub, args) {
1155
+ if (stub.callArgAt < 0) {
1156
+ for (var i = 0, l = args.length; i < l; ++i) {
1157
+ if (!stub.callArgProp && typeof args[i] == "function") {
1158
+ return args[i];
1159
+ }
1160
+
1161
+ if (stub.callArgProp && args[i] &&
1162
+ typeof args[i][stub.callArgProp] == "function") {
1163
+ return args[i][stub.callArgProp];
1164
+ }
1165
+ }
1166
+
1167
+ return null;
1168
+ }
1169
+
1170
+ return args[stub.callArgAt];
1171
+ }
1172
+
1173
+ var join = Array.prototype.join;
1174
+
1175
+ function getCallbackError(stub, func, args) {
1176
+ if (stub.callArgAt < 0) {
1177
+ var msg;
1178
+
1179
+ if (stub.callArgProp) {
1180
+ msg = sinon.functionName(stub) +
1181
+ " expected to yield to '" + stub.callArgProp +
1182
+ "', but no object with such a property was passed."
1183
+ } else {
1184
+ msg = sinon.functionName(stub) +
1185
+ " expected to yield, but no callback was passed."
1186
+ }
1187
+
1188
+ if (args.length > 0) {
1189
+ msg += " Received [" + join.call(args, ", ") + "]";
1190
+ }
1191
+
1192
+ return msg;
1193
+ }
1194
+
1195
+ return "argument at index " + stub.callArgAt + " is not a function: " + func;
1196
+ }
1197
+
1198
+ function callCallback(stub, args) {
1199
+ if (typeof stub.callArgAt == "number") {
1200
+ var func = getCallback(stub, args);
1201
+
1202
+ if (typeof func != "function") {
1203
+ throw new TypeError(getCallbackError(stub, func, args));
1204
+ }
1205
+
1206
+ func.apply(stub.callbackContext, stub.callbackArguments);
1207
+ }
1208
+ }
1209
+
1210
+ var uuid = 0;
1211
+
1212
+ sinon.extend(stub, (function () {
1213
+ var slice = Array.prototype.slice;
1214
+
1215
+ function throwsException(error, message) {
1216
+ if (typeof error == "string") {
1217
+ this.exception = new Error(message || "");
1218
+ this.exception.name = error;
1219
+ } else if (!error) {
1220
+ this.exception = new Error("Error");
1221
+ } else {
1222
+ this.exception = error;
1223
+ }
1224
+
1225
+ return this;
1226
+ }
1227
+
1228
+ return {
1229
+ create: function create() {
1230
+ var functionStub = function () {
1231
+ if (functionStub.exception) {
1232
+ throw functionStub.exception;
1233
+ } else if (typeof functionStub.returnArgAt == 'number') {
1234
+ return arguments[functionStub.returnArgAt];
1235
+ }
1236
+
1237
+ callCallback(functionStub, arguments);
1238
+
1239
+ return functionStub.returnValue;
1240
+ };
1241
+
1242
+ functionStub.id = "stub#" + uuid++;
1243
+ var orig = functionStub;
1244
+ functionStub = sinon.spy.create(functionStub);
1245
+ functionStub.func = orig;
1246
+
1247
+ sinon.extend(functionStub, stub);
1248
+ functionStub._create = sinon.stub.create;
1249
+ functionStub.displayName = "stub";
1250
+ functionStub.toString = sinon.functionToString;
1251
+
1252
+ return functionStub;
1253
+ },
1254
+
1255
+ returns: function returns(value) {
1256
+ this.returnValue = value;
1257
+
1258
+ return this;
1259
+ },
1260
+
1261
+ returnsArg: function returnsArg(pos) {
1262
+ if (typeof pos != "number") {
1263
+ throw new TypeError("argument index is not number");
1264
+ }
1265
+
1266
+ this.returnArgAt = pos;
1267
+
1268
+ return this;
1269
+ },
1270
+
1271
+ "throws": throwsException,
1272
+ throwsException: throwsException,
1273
+
1274
+ callsArg: function callsArg(pos) {
1275
+ if (typeof pos != "number") {
1276
+ throw new TypeError("argument index is not number");
1277
+ }
1278
+
1279
+ this.callArgAt = pos;
1280
+ this.callbackArguments = [];
1281
+
1282
+ return this;
1283
+ },
1284
+
1285
+ callsArgOn: function callsArgOn(pos, context) {
1286
+ if (typeof pos != "number") {
1287
+ throw new TypeError("argument index is not number");
1288
+ }
1289
+ if (typeof context != "object") {
1290
+ throw new TypeError("argument context is not an object");
1291
+ }
1292
+
1293
+ this.callArgAt = pos;
1294
+ this.callbackArguments = [];
1295
+ this.callbackContext = context;
1296
+
1297
+ return this;
1298
+ },
1299
+
1300
+ callsArgWith: function callsArgWith(pos) {
1301
+ if (typeof pos != "number") {
1302
+ throw new TypeError("argument index is not number");
1303
+ }
1304
+
1305
+ this.callArgAt = pos;
1306
+ this.callbackArguments = slice.call(arguments, 1);
1307
+
1308
+ return this;
1309
+ },
1310
+
1311
+ callsArgOnWith: function callsArgWith(pos, context) {
1312
+ if (typeof pos != "number") {
1313
+ throw new TypeError("argument index is not number");
1314
+ }
1315
+ if (typeof context != "object") {
1316
+ throw new TypeError("argument context is not an object");
1317
+ }
1318
+
1319
+ this.callArgAt = pos;
1320
+ this.callbackArguments = slice.call(arguments, 2);
1321
+ this.callbackContext = context;
1322
+
1323
+ return this;
1324
+ },
1325
+
1326
+ yields: function () {
1327
+ this.callArgAt = -1;
1328
+ this.callbackArguments = slice.call(arguments, 0);
1329
+
1330
+ return this;
1331
+ },
1332
+
1333
+ yieldsOn: function (context) {
1334
+ if (typeof context != "object") {
1335
+ throw new TypeError("argument context is not an object");
1336
+ }
1337
+
1338
+ this.callArgAt = -1;
1339
+ this.callbackArguments = slice.call(arguments, 1);
1340
+ this.callbackContext = context;
1341
+
1342
+ return this;
1343
+ },
1344
+
1345
+ yieldsTo: function (prop) {
1346
+ this.callArgAt = -1;
1347
+ this.callArgProp = prop;
1348
+ this.callbackArguments = slice.call(arguments, 1);
1349
+
1350
+ return this;
1351
+ },
1352
+
1353
+ yieldsToOn: function (prop, context) {
1354
+ if (typeof context != "object") {
1355
+ throw new TypeError("argument context is not an object");
1356
+ }
1357
+
1358
+ this.callArgAt = -1;
1359
+ this.callArgProp = prop;
1360
+ this.callbackArguments = slice.call(arguments, 2);
1361
+ this.callbackContext = context;
1362
+
1363
+ return this;
1364
+ }
1365
+ };
1366
+ }()));
1367
+
1368
+ if (commonJSModule) {
1369
+ module.exports = stub;
1370
+ } else {
1371
+ sinon.stub = stub;
1372
+ }
1373
+ }(typeof sinon == "object" && sinon || null));
1374
+
1375
+ /**
1376
+ * @depend ../sinon.js
1377
+ * @depend stub.js
1378
+ */
1379
+ /*jslint eqeqeq: false, onevar: false, nomen: false*/
1380
+ /*global module, require, sinon*/
1381
+ /**
1382
+ * Mock functions.
1383
+ *
1384
+ * @author Christian Johansen (christian@cjohansen.no)
1385
+ * @license BSD
1386
+ *
1387
+ * Copyright (c) 2010-2011 Christian Johansen
1388
+ */
1389
+
1390
+ (function (sinon) {
1391
+ var commonJSModule = typeof module == "object" && typeof require == "function";
1392
+ var push = [].push;
1393
+
1394
+ if (!sinon && commonJSModule) {
1395
+ sinon = require("../sinon");
1396
+ }
1397
+
1398
+ if (!sinon) {
1399
+ return;
1400
+ }
1401
+
1402
+ function mock(object) {
1403
+ if (!object) {
1404
+ return sinon.expectation.create("Anonymous mock");
1405
+ }
1406
+
1407
+ return mock.create(object);
1408
+ }
1409
+
1410
+ sinon.mock = mock;
1411
+
1412
+ sinon.extend(mock, (function () {
1413
+ function each(collection, callback) {
1414
+ if (!collection) {
1415
+ return;
1416
+ }
1417
+
1418
+ for (var i = 0, l = collection.length; i < l; i += 1) {
1419
+ callback(collection[i]);
1420
+ }
1421
+ }
1422
+
1423
+ return {
1424
+ create: function create(object) {
1425
+ if (!object) {
1426
+ throw new TypeError("object is null");
1427
+ }
1428
+
1429
+ var mockObject = sinon.extend({}, mock);
1430
+ mockObject.object = object;
1431
+ delete mockObject.create;
1432
+
1433
+ return mockObject;
1434
+ },
1435
+
1436
+ expects: function expects(method) {
1437
+ if (!method) {
1438
+ throw new TypeError("method is falsy");
1439
+ }
1440
+
1441
+ if (!this.expectations) {
1442
+ this.expectations = {};
1443
+ this.proxies = [];
1444
+ }
1445
+
1446
+ if (!this.expectations[method]) {
1447
+ this.expectations[method] = [];
1448
+ var mockObject = this;
1449
+
1450
+ sinon.wrapMethod(this.object, method, function () {
1451
+ return mockObject.invokeMethod(method, this, arguments);
1452
+ });
1453
+
1454
+ push.call(this.proxies, method);
1455
+ }
1456
+
1457
+ var expectation = sinon.expectation.create(method);
1458
+ push.call(this.expectations[method], expectation);
1459
+
1460
+ return expectation;
1461
+ },
1462
+
1463
+ restore: function restore() {
1464
+ var object = this.object;
1465
+
1466
+ each(this.proxies, function (proxy) {
1467
+ if (typeof object[proxy].restore == "function") {
1468
+ object[proxy].restore();
1469
+ }
1470
+ });
1471
+ },
1472
+
1473
+ verify: function verify() {
1474
+ var expectations = this.expectations || {};
1475
+ var messages = [], met = [];
1476
+
1477
+ each(this.proxies, function (proxy) {
1478
+ each(expectations[proxy], function (expectation) {
1479
+ if (!expectation.met()) {
1480
+ push.call(messages, expectation.toString());
1481
+ } else {
1482
+ push.call(met, expectation.toString());
1483
+ }
1484
+ });
1485
+ });
1486
+
1487
+ this.restore();
1488
+
1489
+ if (messages.length > 0) {
1490
+ sinon.expectation.fail(messages.concat(met).join("\n"));
1491
+ }
1492
+
1493
+ return true;
1494
+ },
1495
+
1496
+ invokeMethod: function invokeMethod(method, thisValue, args) {
1497
+ var expectations = this.expectations && this.expectations[method];
1498
+ var length = expectations && expectations.length || 0;
1499
+
1500
+ for (var i = 0; i < length; i += 1) {
1501
+ if (!expectations[i].met() &&
1502
+ expectations[i].allowsCall(thisValue, args)) {
1503
+ return expectations[i].apply(thisValue, args);
1504
+ }
1505
+ }
1506
+
1507
+ var messages = [];
1508
+
1509
+ for (i = 0; i < length; i += 1) {
1510
+ push.call(messages, " " + expectations[i].toString());
1511
+ }
1512
+
1513
+ messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
1514
+ proxy: method,
1515
+ args: args
1516
+ }));
1517
+
1518
+ sinon.expectation.fail(messages.join("\n"));
1519
+ }
1520
+ };
1521
+ }()));
1522
+
1523
+ var times = sinon.timesInWords;
1524
+
1525
+ sinon.expectation = (function () {
1526
+ var slice = Array.prototype.slice;
1527
+ var _invoke = sinon.spy.invoke;
1528
+
1529
+ function callCountInWords(callCount) {
1530
+ if (callCount == 0) {
1531
+ return "never called";
1532
+ } else {
1533
+ return "called " + times(callCount);
1534
+ }
1535
+ }
1536
+
1537
+ function expectedCallCountInWords(expectation) {
1538
+ var min = expectation.minCalls;
1539
+ var max = expectation.maxCalls;
1540
+
1541
+ if (typeof min == "number" && typeof max == "number") {
1542
+ var str = times(min);
1543
+
1544
+ if (min != max) {
1545
+ str = "at least " + str + " and at most " + times(max);
1546
+ }
1547
+
1548
+ return str;
1549
+ }
1550
+
1551
+ if (typeof min == "number") {
1552
+ return "at least " + times(min);
1553
+ }
1554
+
1555
+ return "at most " + times(max);
1556
+ }
1557
+
1558
+ function receivedMinCalls(expectation) {
1559
+ var hasMinLimit = typeof expectation.minCalls == "number";
1560
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
1561
+ }
1562
+
1563
+ function receivedMaxCalls(expectation) {
1564
+ if (typeof expectation.maxCalls != "number") {
1565
+ return false;
1566
+ }
1567
+
1568
+ return expectation.callCount == expectation.maxCalls;
1569
+ }
1570
+
1571
+ return {
1572
+ minCalls: 1,
1573
+ maxCalls: 1,
1574
+
1575
+ create: function create(methodName) {
1576
+ var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
1577
+ delete expectation.create;
1578
+ expectation.method = methodName;
1579
+
1580
+ return expectation;
1581
+ },
1582
+
1583
+ invoke: function invoke(func, thisValue, args) {
1584
+ this.verifyCallAllowed(thisValue, args);
1585
+
1586
+ return _invoke.apply(this, arguments);
1587
+ },
1588
+
1589
+ atLeast: function atLeast(num) {
1590
+ if (typeof num != "number") {
1591
+ throw new TypeError("'" + num + "' is not number");
1592
+ }
1593
+
1594
+ if (!this.limitsSet) {
1595
+ this.maxCalls = null;
1596
+ this.limitsSet = true;
1597
+ }
1598
+
1599
+ this.minCalls = num;
1600
+
1601
+ return this;
1602
+ },
1603
+
1604
+ atMost: function atMost(num) {
1605
+ if (typeof num != "number") {
1606
+ throw new TypeError("'" + num + "' is not number");
1607
+ }
1608
+
1609
+ if (!this.limitsSet) {
1610
+ this.minCalls = null;
1611
+ this.limitsSet = true;
1612
+ }
1613
+
1614
+ this.maxCalls = num;
1615
+
1616
+ return this;
1617
+ },
1618
+
1619
+ never: function never() {
1620
+ return this.exactly(0);
1621
+ },
1622
+
1623
+ once: function once() {
1624
+ return this.exactly(1);
1625
+ },
1626
+
1627
+ twice: function twice() {
1628
+ return this.exactly(2);
1629
+ },
1630
+
1631
+ thrice: function thrice() {
1632
+ return this.exactly(3);
1633
+ },
1634
+
1635
+ exactly: function exactly(num) {
1636
+ if (typeof num != "number") {
1637
+ throw new TypeError("'" + num + "' is not a number");
1638
+ }
1639
+
1640
+ this.atLeast(num);
1641
+ return this.atMost(num);
1642
+ },
1643
+
1644
+ met: function met() {
1645
+ return !this.failed && receivedMinCalls(this);
1646
+ },
1647
+
1648
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
1649
+ if (receivedMaxCalls(this)) {
1650
+ this.failed = true;
1651
+ sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
1652
+ }
1653
+
1654
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
1655
+ sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
1656
+ this.expectedThis);
1657
+ }
1658
+
1659
+ if (!("expectedArguments" in this)) {
1660
+ return;
1661
+ }
1662
+
1663
+ if (!args || args.length === 0) {
1664
+ sinon.expectation.fail(this.method + " received no arguments, expected " +
1665
+ this.expectedArguments.join());
1666
+ }
1667
+
1668
+ if (args.length < this.expectedArguments.length) {
1669
+ sinon.expectation.fail(this.method + " received too few arguments (" + args.join() +
1670
+ "), expected " + this.expectedArguments.join());
1671
+ }
1672
+
1673
+ if (this.expectsExactArgCount &&
1674
+ args.length != this.expectedArguments.length) {
1675
+ sinon.expectation.fail(this.method + " received too many arguments (" + args.join() +
1676
+ "), expected " + this.expectedArguments.join());
1677
+ }
1678
+
1679
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
1680
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
1681
+ sinon.expectation.fail(this.method + " received wrong arguments (" + args.join() +
1682
+ "), expected " + this.expectedArguments.join());
1683
+ }
1684
+ }
1685
+ },
1686
+
1687
+ allowsCall: function allowsCall(thisValue, args) {
1688
+ if (this.met()) {
1689
+ return false;
1690
+ }
1691
+
1692
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
1693
+ return false;
1694
+ }
1695
+
1696
+ if (!("expectedArguments" in this)) {
1697
+ return true;
1698
+ }
1699
+
1700
+ args = args || [];
1701
+
1702
+ if (args.length < this.expectedArguments.length) {
1703
+ return false;
1704
+ }
1705
+
1706
+ if (this.expectsExactArgCount &&
1707
+ args.length != this.expectedArguments.length) {
1708
+ return false;
1709
+ }
1710
+
1711
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
1712
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
1713
+ return false;
1714
+ }
1715
+ }
1716
+
1717
+ return true;
1718
+ },
1719
+
1720
+ withArgs: function withArgs() {
1721
+ this.expectedArguments = slice.call(arguments);
1722
+ return this;
1723
+ },
1724
+
1725
+ withExactArgs: function withExactArgs() {
1726
+ this.withArgs.apply(this, arguments);
1727
+ this.expectsExactArgCount = true;
1728
+ return this;
1729
+ },
1730
+
1731
+ on: function on(thisValue) {
1732
+ this.expectedThis = thisValue;
1733
+ return this;
1734
+ },
1735
+
1736
+ toString: function () {
1737
+ var args = (this.expectedArguments || []).slice();
1738
+
1739
+ if (!this.expectsExactArgCount) {
1740
+ push.call(args, "[...]");
1741
+ }
1742
+
1743
+ var callStr = sinon.spyCall.toString.call({
1744
+ proxy: this.method, args: args
1745
+ });
1746
+
1747
+ var message = callStr.replace(", [...", "[, ...") + " " +
1748
+ expectedCallCountInWords(this);
1749
+
1750
+ if (this.met()) {
1751
+ return "Expectation met: " + message;
1752
+ }
1753
+
1754
+ return "Expected " + message + " (" +
1755
+ callCountInWords(this.callCount) + ")";
1756
+ },
1757
+
1758
+ verify: function verify() {
1759
+ if (!this.met()) {
1760
+ sinon.expectation.fail(this.toString());
1761
+ }
1762
+
1763
+ return true;
1764
+ },
1765
+
1766
+ fail: function (message) {
1767
+ var exception = new Error(message);
1768
+ exception.name = "ExpectationError";
1769
+
1770
+ throw exception;
1771
+ }
1772
+ };
1773
+ }());
1774
+
1775
+ if (commonJSModule) {
1776
+ module.exports = mock;
1777
+ } else {
1778
+ sinon.mock = mock;
1779
+ }
1780
+ }(typeof sinon == "object" && sinon || null));
1781
+
1782
+ /**
1783
+ * @depend ../sinon.js
1784
+ * @depend stub.js
1785
+ * @depend mock.js
1786
+ */
1787
+ /*jslint eqeqeq: false, onevar: false, forin: true*/
1788
+ /*global module, require, sinon*/
1789
+ /**
1790
+ * Collections of stubs, spies and mocks.
1791
+ *
1792
+ * @author Christian Johansen (christian@cjohansen.no)
1793
+ * @license BSD
1794
+ *
1795
+ * Copyright (c) 2010-2011 Christian Johansen
1796
+ */
1797
+
1798
+ (function (sinon) {
1799
+ var commonJSModule = typeof module == "object" && typeof require == "function";
1800
+ var push = [].push;
1801
+
1802
+ if (!sinon && commonJSModule) {
1803
+ sinon = require("../sinon");
1804
+ }
1805
+
1806
+ if (!sinon) {
1807
+ return;
1808
+ }
1809
+
1810
+ function getFakes(fakeCollection) {
1811
+ if (!fakeCollection.fakes) {
1812
+ fakeCollection.fakes = [];
1813
+ }
1814
+
1815
+ return fakeCollection.fakes;
1816
+ }
1817
+
1818
+ function each(fakeCollection, method) {
1819
+ var fakes = getFakes(fakeCollection);
1820
+
1821
+ for (var i = 0, l = fakes.length; i < l; i += 1) {
1822
+ if (typeof fakes[i][method] == "function") {
1823
+ fakes[i][method]();
1824
+ }
1825
+ }
1826
+ }
1827
+
1828
+ function compact(fakeCollection) {
1829
+ var fakes = getFakes(fakeCollection);
1830
+ var i = 0;
1831
+ while (i < fakes.length) {
1832
+ fakes.splice(i, 1);
1833
+ }
1834
+ }
1835
+
1836
+ var collection = {
1837
+ verify: function resolve() {
1838
+ each(this, "verify");
1839
+ },
1840
+
1841
+ restore: function restore() {
1842
+ each(this, "restore");
1843
+ compact(this);
1844
+ },
1845
+
1846
+ verifyAndRestore: function verifyAndRestore() {
1847
+ var exception;
1848
+
1849
+ try {
1850
+ this.verify();
1851
+ } catch (e) {
1852
+ exception = e;
1853
+ }
1854
+
1855
+ this.restore();
1856
+
1857
+ if (exception) {
1858
+ throw exception;
1859
+ }
1860
+ },
1861
+
1862
+ add: function add(fake) {
1863
+ push.call(getFakes(this), fake);
1864
+ return fake;
1865
+ },
1866
+
1867
+ spy: function spy() {
1868
+ return this.add(sinon.spy.apply(sinon, arguments));
1869
+ },
1870
+
1871
+ stub: function stub(object, property, value) {
1872
+ if (property) {
1873
+ var original = object[property];
1874
+
1875
+ if (typeof original != "function") {
1876
+ if (!object.hasOwnProperty(property)) {
1877
+ throw new TypeError("Cannot stub non-existent own property " + property);
1878
+ }
1879
+
1880
+ object[property] = value;
1881
+
1882
+ return this.add({
1883
+ restore: function () {
1884
+ object[property] = original;
1885
+ }
1886
+ });
1887
+ }
1888
+ }
1889
+
1890
+ return this.add(sinon.stub.apply(sinon, arguments));
1891
+ },
1892
+
1893
+ mock: function mock() {
1894
+ return this.add(sinon.mock.apply(sinon, arguments));
1895
+ },
1896
+
1897
+ inject: function inject(obj) {
1898
+ var col = this;
1899
+
1900
+ obj.spy = function () {
1901
+ return col.spy.apply(col, arguments);
1902
+ };
1903
+
1904
+ obj.stub = function () {
1905
+ return col.stub.apply(col, arguments);
1906
+ };
1907
+
1908
+ obj.mock = function () {
1909
+ return col.mock.apply(col, arguments);
1910
+ };
1911
+
1912
+ return obj;
1913
+ }
1914
+ };
1915
+
1916
+ if (commonJSModule) {
1917
+ module.exports = collection;
1918
+ } else {
1919
+ sinon.collection = collection;
1920
+ }
1921
+ }(typeof sinon == "object" && sinon || null));
1922
+
1923
+ /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
1924
+ /*global module, require, window*/
1925
+ /**
1926
+ * Fake timer API
1927
+ * setTimeout
1928
+ * setInterval
1929
+ * clearTimeout
1930
+ * clearInterval
1931
+ * tick
1932
+ * reset
1933
+ * Date
1934
+ *
1935
+ * Inspired by jsUnitMockTimeOut from JsUnit
1936
+ *
1937
+ * @author Christian Johansen (christian@cjohansen.no)
1938
+ * @license BSD
1939
+ *
1940
+ * Copyright (c) 2010-2011 Christian Johansen
1941
+ */
1942
+
1943
+ if (typeof sinon == "undefined") {
1944
+ var sinon = {};
1945
+ }
1946
+
1947
+ (function (global) {
1948
+ var id = 1;
1949
+
1950
+ function addTimer(args, recurring) {
1951
+ if (args.length === 0) {
1952
+ throw new Error("Function requires at least 1 parameter");
1953
+ }
1954
+
1955
+ var toId = id++;
1956
+ var delay = args[1] || 0;
1957
+
1958
+ if (!this.timeouts) {
1959
+ this.timeouts = {};
1960
+ }
1961
+
1962
+ this.timeouts[toId] = {
1963
+ id: toId,
1964
+ func: args[0],
1965
+ callAt: this.now + delay
1966
+ };
1967
+
1968
+ if (recurring === true) {
1969
+ this.timeouts[toId].interval = delay;
1970
+ }
1971
+
1972
+ return toId;
1973
+ }
1974
+
1975
+ function parseTime(str) {
1976
+ if (!str) {
1977
+ return 0;
1978
+ }
1979
+
1980
+ var strings = str.split(":");
1981
+ var l = strings.length, i = l;
1982
+ var ms = 0, parsed;
1983
+
1984
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
1985
+ throw new Error("tick only understands numbers and 'h:m:s'");
1986
+ }
1987
+
1988
+ while (i--) {
1989
+ parsed = parseInt(strings[i], 10);
1990
+
1991
+ if (parsed >= 60) {
1992
+ throw new Error("Invalid time " + str);
1993
+ }
1994
+
1995
+ ms += parsed * Math.pow(60, (l - i - 1));
1996
+ }
1997
+
1998
+ return ms * 1000;
1999
+ }
2000
+
2001
+ function createObject(object) {
2002
+ var newObject;
2003
+
2004
+ if (Object.create) {
2005
+ newObject = Object.create(object);
2006
+ } else {
2007
+ var F = function () {};
2008
+ F.prototype = object;
2009
+ newObject = new F();
2010
+ }
2011
+
2012
+ newObject.Date.clock = newObject;
2013
+ return newObject;
2014
+ }
2015
+
2016
+ sinon.clock = {
2017
+ now: 0,
2018
+
2019
+ create: function create(now) {
2020
+ var clock = createObject(this);
2021
+
2022
+ if (typeof now == "number") {
2023
+ clock.now = now;
2024
+ }
2025
+
2026
+ if (!!now && typeof now == "object") {
2027
+ throw new TypeError("now should be milliseconds since UNIX epoch");
2028
+ }
2029
+
2030
+ return clock;
2031
+ },
2032
+
2033
+ setTimeout: function setTimeout(callback, timeout) {
2034
+ return addTimer.call(this, arguments, false);
2035
+ },
2036
+
2037
+ clearTimeout: function clearTimeout(timerId) {
2038
+ if (!this.timeouts) {
2039
+ this.timeouts = [];
2040
+ }
2041
+
2042
+ if (timerId in this.timeouts) {
2043
+ delete this.timeouts[timerId];
2044
+ }
2045
+ },
2046
+
2047
+ setInterval: function setInterval(callback, timeout) {
2048
+ return addTimer.call(this, arguments, true);
2049
+ },
2050
+
2051
+ clearInterval: function clearInterval(timerId) {
2052
+ this.clearTimeout(timerId);
2053
+ },
2054
+
2055
+ tick: function tick(ms) {
2056
+ ms = typeof ms == "number" ? ms : parseTime(ms);
2057
+ var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
2058
+ var timer = this.firstTimerInRange(tickFrom, tickTo);
2059
+
2060
+ var firstException;
2061
+ while (timer && tickFrom <= tickTo) {
2062
+ if (this.timeouts[timer.id]) {
2063
+ tickFrom = this.now = timer.callAt;
2064
+ try {
2065
+ this.callTimer(timer);
2066
+ } catch (e) {
2067
+ firstException = firstException || e;
2068
+ }
2069
+ }
2070
+
2071
+ timer = this.firstTimerInRange(previous, tickTo);
2072
+ previous = tickFrom;
2073
+ }
2074
+
2075
+ this.now = tickTo;
2076
+
2077
+ if (firstException) {
2078
+ throw firstException;
2079
+ }
2080
+ },
2081
+
2082
+ firstTimerInRange: function (from, to) {
2083
+ var timer, smallest, originalTimer;
2084
+
2085
+ for (var id in this.timeouts) {
2086
+ if (this.timeouts.hasOwnProperty(id)) {
2087
+ if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
2088
+ continue;
2089
+ }
2090
+
2091
+ if (!smallest || this.timeouts[id].callAt < smallest) {
2092
+ originalTimer = this.timeouts[id];
2093
+ smallest = this.timeouts[id].callAt;
2094
+
2095
+ timer = {
2096
+ func: this.timeouts[id].func,
2097
+ callAt: this.timeouts[id].callAt,
2098
+ interval: this.timeouts[id].interval,
2099
+ id: this.timeouts[id].id
2100
+ };
2101
+ }
2102
+ }
2103
+ }
2104
+
2105
+ return timer || null;
2106
+ },
2107
+
2108
+ callTimer: function (timer) {
2109
+ try {
2110
+ if (typeof timer.func == "function") {
2111
+ timer.func.call(null);
2112
+ } else {
2113
+ eval(timer.func);
2114
+ }
2115
+ } catch (e) {
2116
+ var exception = e;
2117
+ }
2118
+
2119
+ if (!this.timeouts[timer.id]) {
2120
+ if (exception) {
2121
+ throw exception;
2122
+ }
2123
+ return;
2124
+ }
2125
+
2126
+ if (typeof timer.interval == "number") {
2127
+ this.timeouts[timer.id].callAt += timer.interval;
2128
+ } else {
2129
+ delete this.timeouts[timer.id];
2130
+ }
2131
+
2132
+ if (exception) {
2133
+ throw exception;
2134
+ }
2135
+ },
2136
+
2137
+ reset: function reset() {
2138
+ this.timeouts = {};
2139
+ },
2140
+
2141
+ Date: (function () {
2142
+ var NativeDate = Date;
2143
+
2144
+ function ClockDate(year, month, date, hour, minute, second, ms) {
2145
+ // Defensive and verbose to avoid potential harm in passing
2146
+ // explicit undefined when user does not pass argument
2147
+ switch (arguments.length) {
2148
+ case 0:
2149
+ return new NativeDate(ClockDate.clock.now);
2150
+ case 1:
2151
+ return new NativeDate(year);
2152
+ case 2:
2153
+ return new NativeDate(year, month);
2154
+ case 3:
2155
+ return new NativeDate(year, month, date);
2156
+ case 4:
2157
+ return new NativeDate(year, month, date, hour);
2158
+ case 5:
2159
+ return new NativeDate(year, month, date, hour, minute);
2160
+ case 6:
2161
+ return new NativeDate(year, month, date, hour, minute, second);
2162
+ default:
2163
+ return new NativeDate(year, month, date, hour, minute, second, ms);
2164
+ }
2165
+ }
2166
+
2167
+ return mirrorDateProperties(ClockDate, NativeDate);
2168
+ }())
2169
+ };
2170
+
2171
+ function mirrorDateProperties(target, source) {
2172
+ if (source.now) {
2173
+ target.now = function now() {
2174
+ return target.clock.now;
2175
+ };
2176
+ } else {
2177
+ delete target.now;
2178
+ }
2179
+
2180
+ if (source.toSource) {
2181
+ target.toSource = function toSource() {
2182
+ return source.toSource();
2183
+ };
2184
+ } else {
2185
+ delete target.toSource;
2186
+ }
2187
+
2188
+ target.toString = function toString() {
2189
+ return source.toString();
2190
+ };
2191
+
2192
+ target.prototype = source.prototype;
2193
+ target.parse = source.parse;
2194
+ target.UTC = source.UTC;
2195
+ target.prototype.toUTCString = source.prototype.toUTCString;
2196
+ return target;
2197
+ }
2198
+
2199
+ var methods = ["Date", "setTimeout", "setInterval",
2200
+ "clearTimeout", "clearInterval"];
2201
+
2202
+ function restore() {
2203
+ var method;
2204
+
2205
+ for (var i = 0, l = this.methods.length; i < l; i++) {
2206
+ method = this.methods[i];
2207
+ global[method] = this["_" + method];
2208
+ }
2209
+ }
2210
+
2211
+ function stubGlobal(method, clock) {
2212
+ clock["_" + method] = global[method];
2213
+
2214
+ if (method == "Date") {
2215
+ var date = mirrorDateProperties(clock[method], global[method]);
2216
+ global[method] = date;
2217
+ } else {
2218
+ global[method] = function () {
2219
+ return clock[method].apply(clock, arguments);
2220
+ };
2221
+
2222
+ for (var prop in clock[method]) {
2223
+ if (clock[method].hasOwnProperty(prop)) {
2224
+ global[method][prop] = clock[method][prop];
2225
+ }
2226
+ }
2227
+ }
2228
+
2229
+ global[method].clock = clock;
2230
+ }
2231
+
2232
+ sinon.useFakeTimers = function useFakeTimers(now) {
2233
+ var clock = sinon.clock.create(now);
2234
+ clock.restore = restore;
2235
+ clock.methods = Array.prototype.slice.call(arguments,
2236
+ typeof now == "number" ? 1 : 0);
2237
+
2238
+ if (clock.methods.length === 0) {
2239
+ clock.methods = methods;
2240
+ }
2241
+
2242
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
2243
+ stubGlobal(clock.methods[i], clock);
2244
+ }
2245
+
2246
+ return clock;
2247
+ };
2248
+ }(typeof global != "undefined" && typeof global !== "function" ? global : this));
2249
+
2250
+ sinon.timers = {
2251
+ setTimeout: setTimeout,
2252
+ clearTimeout: clearTimeout,
2253
+ setInterval: setInterval,
2254
+ clearInterval: clearInterval,
2255
+ Date: Date
2256
+ };
2257
+
2258
+ if (typeof module == "object" && typeof require == "function") {
2259
+ module.exports = sinon;
2260
+ }
2261
+
2262
+ /*jslint eqeqeq: false, onevar: false*/
2263
+ /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
2264
+ /**
2265
+ * Minimal Event interface implementation
2266
+ *
2267
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
2268
+ * Modifications and tests by Christian Johansen.
2269
+ *
2270
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
2271
+ * @author Christian Johansen (christian@cjohansen.no)
2272
+ * @license BSD
2273
+ *
2274
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
2275
+ */
2276
+
2277
+ if (typeof sinon == "undefined") {
2278
+ this.sinon = {};
2279
+ }
2280
+
2281
+ (function () {
2282
+ var push = [].push;
2283
+
2284
+ sinon.Event = function Event(type, bubbles, cancelable) {
2285
+ this.initEvent(type, bubbles, cancelable);
2286
+ };
2287
+
2288
+ sinon.Event.prototype = {
2289
+ initEvent: function(type, bubbles, cancelable) {
2290
+ this.type = type;
2291
+ this.bubbles = bubbles;
2292
+ this.cancelable = cancelable;
2293
+ },
2294
+
2295
+ stopPropagation: function () {},
2296
+
2297
+ preventDefault: function () {
2298
+ this.defaultPrevented = true;
2299
+ }
2300
+ };
2301
+
2302
+ sinon.EventTarget = {
2303
+ addEventListener: function addEventListener(event, listener, useCapture) {
2304
+ this.eventListeners = this.eventListeners || {};
2305
+ this.eventListeners[event] = this.eventListeners[event] || [];
2306
+ push.call(this.eventListeners[event], listener);
2307
+ },
2308
+
2309
+ removeEventListener: function removeEventListener(event, listener, useCapture) {
2310
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
2311
+
2312
+ for (var i = 0, l = listeners.length; i < l; ++i) {
2313
+ if (listeners[i] == listener) {
2314
+ return listeners.splice(i, 1);
2315
+ }
2316
+ }
2317
+ },
2318
+
2319
+ dispatchEvent: function dispatchEvent(event) {
2320
+ var type = event.type;
2321
+ var listeners = this.eventListeners && this.eventListeners[type] || [];
2322
+
2323
+ for (var i = 0; i < listeners.length; i++) {
2324
+ if (typeof listeners[i] == "function") {
2325
+ listeners[i].call(this, event);
2326
+ } else {
2327
+ listeners[i].handleEvent(event);
2328
+ }
2329
+ }
2330
+
2331
+ return !!event.defaultPrevented;
2332
+ }
2333
+ };
2334
+ }());
2335
+
2336
+ /**
2337
+ * @depend event.js
2338
+ */
2339
+ /*jslint eqeqeq: false, onevar: false*/
2340
+ /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
2341
+ /**
2342
+ * Fake XMLHttpRequest object
2343
+ *
2344
+ * @author Christian Johansen (christian@cjohansen.no)
2345
+ * @license BSD
2346
+ *
2347
+ * Copyright (c) 2010-2011 Christian Johansen
2348
+ */
2349
+
2350
+ if (typeof sinon == "undefined") {
2351
+ this.sinon = {};
2352
+ }
2353
+ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2354
+
2355
+ // wrapper for global
2356
+ (function(global) {
2357
+ var xhr = sinon.xhr;
2358
+ xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
2359
+ xhr.GlobalActiveXObject = global.ActiveXObject;
2360
+ xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
2361
+ xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
2362
+ xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
2363
+ ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
2364
+
2365
+ /*jsl:ignore*/
2366
+ var unsafeHeaders = {
2367
+ "Accept-Charset": true,
2368
+ "Accept-Encoding": true,
2369
+ "Connection": true,
2370
+ "Content-Length": true,
2371
+ "Cookie": true,
2372
+ "Cookie2": true,
2373
+ "Content-Transfer-Encoding": true,
2374
+ "Date": true,
2375
+ "Expect": true,
2376
+ "Host": true,
2377
+ "Keep-Alive": true,
2378
+ "Referer": true,
2379
+ "TE": true,
2380
+ "Trailer": true,
2381
+ "Transfer-Encoding": true,
2382
+ "Upgrade": true,
2383
+ "User-Agent": true,
2384
+ "Via": true
2385
+ };
2386
+ /*jsl:end*/
2387
+
2388
+ function FakeXMLHttpRequest() {
2389
+ this.readyState = FakeXMLHttpRequest.UNSENT;
2390
+ this.requestHeaders = {};
2391
+ this.requestBody = null;
2392
+ this.status = 0;
2393
+ this.statusText = "";
2394
+
2395
+ if (typeof FakeXMLHttpRequest.onCreate == "function") {
2396
+ FakeXMLHttpRequest.onCreate(this);
2397
+ }
2398
+ }
2399
+
2400
+ function verifyState(xhr) {
2401
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
2402
+ throw new Error("INVALID_STATE_ERR");
2403
+ }
2404
+
2405
+ if (xhr.sendFlag) {
2406
+ throw new Error("INVALID_STATE_ERR");
2407
+ }
2408
+ }
2409
+
2410
+ // filtering to enable a white-list version of Sinon FakeXhr,
2411
+ // where whitelisted requests are passed through to real XHR
2412
+ function each(collection, callback) {
2413
+ if (!collection) return;
2414
+ for (var i = 0, l = collection.length; i < l; i += 1) {
2415
+ callback(collection[i]);
2416
+ }
2417
+ }
2418
+ function some(collection, callback) {
2419
+ for (var index = 0; index < collection.length; index++) {
2420
+ if(callback(collection[index]) === true) return true;
2421
+ };
2422
+ return false;
2423
+ }
2424
+ // largest arity in XHR is 5 - XHR#open
2425
+ var apply = function(obj,method,args) {
2426
+ switch(args.length) {
2427
+ case 0: return obj[method]();
2428
+ case 1: return obj[method](args[0]);
2429
+ case 2: return obj[method](args[0],args[1]);
2430
+ case 3: return obj[method](args[0],args[1],args[2]);
2431
+ case 4: return obj[method](args[0],args[1],args[2],args[3]);
2432
+ case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
2433
+ };
2434
+ };
2435
+
2436
+ FakeXMLHttpRequest.filters = [];
2437
+ FakeXMLHttpRequest.addFilter = function(fn) {
2438
+ this.filters.push(fn)
2439
+ };
2440
+ var IE6Re = /MSIE 6/;
2441
+ FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
2442
+ var xhr = new sinon.xhr.workingXHR();
2443
+ each(["open","setRequestHeader","send","abort","getResponseHeader",
2444
+ "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
2445
+ function(method) {
2446
+ fakeXhr[method] = function() {
2447
+ return apply(xhr,method,arguments);
2448
+ };
2449
+ });
2450
+
2451
+ var copyAttrs = function(args) {
2452
+ each(args, function(attr) {
2453
+ try {
2454
+ fakeXhr[attr] = xhr[attr]
2455
+ } catch(e) {
2456
+ if(!IE6Re.test(navigator.userAgent)) throw e;
2457
+ }
2458
+ });
2459
+ };
2460
+
2461
+ var stateChange = function() {
2462
+ fakeXhr.readyState = xhr.readyState;
2463
+ if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
2464
+ copyAttrs(["status","statusText"]);
2465
+ }
2466
+ if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
2467
+ copyAttrs(["responseText"]);
2468
+ }
2469
+ if(xhr.readyState === FakeXMLHttpRequest.DONE) {
2470
+ copyAttrs(["responseXML"]);
2471
+ }
2472
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
2473
+ };
2474
+ if(xhr.addEventListener) {
2475
+ for(var event in fakeXhr.eventListeners) {
2476
+ if(fakeXhr.eventListeners.hasOwnProperty(event)) {
2477
+ each(fakeXhr.eventListeners[event],function(handler) {
2478
+ xhr.addEventListener(event, handler);
2479
+ });
2480
+ }
2481
+ }
2482
+ xhr.addEventListener("readystatechange",stateChange);
2483
+ } else {
2484
+ xhr.onreadystatechange = stateChange;
2485
+ }
2486
+ apply(xhr,"open",xhrArgs);
2487
+ };
2488
+ FakeXMLHttpRequest.useFilters = false;
2489
+
2490
+ function verifyRequestSent(xhr) {
2491
+ if (xhr.readyState == FakeXMLHttpRequest.DONE) {
2492
+ throw new Error("Request done");
2493
+ }
2494
+ }
2495
+
2496
+ function verifyHeadersReceived(xhr) {
2497
+ if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
2498
+ throw new Error("No headers received");
2499
+ }
2500
+ }
2501
+
2502
+ function verifyResponseBodyType(body) {
2503
+ if (typeof body != "string") {
2504
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
2505
+ body + ", which is not a string.");
2506
+ error.name = "InvalidBodyException";
2507
+ throw error;
2508
+ }
2509
+ }
2510
+
2511
+ sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
2512
+ async: true,
2513
+
2514
+ open: function open(method, url, async, username, password) {
2515
+ this.method = method;
2516
+ this.url = url;
2517
+ this.async = typeof async == "boolean" ? async : true;
2518
+ this.username = username;
2519
+ this.password = password;
2520
+ this.responseText = null;
2521
+ this.responseXML = null;
2522
+ this.requestHeaders = {};
2523
+ this.sendFlag = false;
2524
+ if(sinon.FakeXMLHttpRequest.useFilters === true) {
2525
+ var xhrArgs = arguments;
2526
+ var defake = some(FakeXMLHttpRequest.filters,function(filter) {
2527
+ return filter.apply(this,xhrArgs)
2528
+ });
2529
+ if (defake) {
2530
+ return sinon.FakeXMLHttpRequest.defake(this,arguments);
2531
+ }
2532
+ }
2533
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
2534
+ },
2535
+
2536
+ readyStateChange: function readyStateChange(state) {
2537
+ this.readyState = state;
2538
+
2539
+ if (typeof this.onreadystatechange == "function") {
2540
+ try {
2541
+ this.onreadystatechange();
2542
+ } catch (e) {
2543
+ sinon.logError("Fake XHR onreadystatechange handler", e);
2544
+ }
2545
+ }
2546
+
2547
+ this.dispatchEvent(new sinon.Event("readystatechange"));
2548
+ },
2549
+
2550
+ setRequestHeader: function setRequestHeader(header, value) {
2551
+ verifyState(this);
2552
+
2553
+ if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
2554
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
2555
+ }
2556
+
2557
+ if (this.requestHeaders[header]) {
2558
+ this.requestHeaders[header] += "," + value;
2559
+ } else {
2560
+ this.requestHeaders[header] = value;
2561
+ }
2562
+ },
2563
+
2564
+ // Helps testing
2565
+ setResponseHeaders: function setResponseHeaders(headers) {
2566
+ this.responseHeaders = {};
2567
+
2568
+ for (var header in headers) {
2569
+ if (headers.hasOwnProperty(header)) {
2570
+ this.responseHeaders[header] = headers[header];
2571
+ }
2572
+ }
2573
+
2574
+ if (this.async) {
2575
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
2576
+ }
2577
+ },
2578
+
2579
+ // Currently treats ALL data as a DOMString (i.e. no Document)
2580
+ send: function send(data) {
2581
+ verifyState(this);
2582
+
2583
+ if (!/^(get|head)$/i.test(this.method)) {
2584
+ if (this.requestHeaders["Content-Type"]) {
2585
+ var value = this.requestHeaders["Content-Type"].split(";");
2586
+ this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
2587
+ } else {
2588
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
2589
+ }
2590
+
2591
+ this.requestBody = data;
2592
+ }
2593
+
2594
+ this.errorFlag = false;
2595
+ this.sendFlag = this.async;
2596
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
2597
+
2598
+ if (typeof this.onSend == "function") {
2599
+ this.onSend(this);
2600
+ }
2601
+ },
2602
+
2603
+ abort: function abort() {
2604
+ this.aborted = true;
2605
+ this.responseText = null;
2606
+ this.errorFlag = true;
2607
+ this.requestHeaders = {};
2608
+
2609
+ if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
2610
+ this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
2611
+ this.sendFlag = false;
2612
+ }
2613
+
2614
+ this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
2615
+ },
2616
+
2617
+ getResponseHeader: function getResponseHeader(header) {
2618
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
2619
+ return null;
2620
+ }
2621
+
2622
+ if (/^Set-Cookie2?$/i.test(header)) {
2623
+ return null;
2624
+ }
2625
+
2626
+ header = header.toLowerCase();
2627
+
2628
+ for (var h in this.responseHeaders) {
2629
+ if (h.toLowerCase() == header) {
2630
+ return this.responseHeaders[h];
2631
+ }
2632
+ }
2633
+
2634
+ return null;
2635
+ },
2636
+
2637
+ getAllResponseHeaders: function getAllResponseHeaders() {
2638
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
2639
+ return "";
2640
+ }
2641
+
2642
+ var headers = "";
2643
+
2644
+ for (var header in this.responseHeaders) {
2645
+ if (this.responseHeaders.hasOwnProperty(header) &&
2646
+ !/^Set-Cookie2?$/i.test(header)) {
2647
+ headers += header + ": " + this.responseHeaders[header] + "\r\n";
2648
+ }
2649
+ }
2650
+
2651
+ return headers;
2652
+ },
2653
+
2654
+ setResponseBody: function setResponseBody(body) {
2655
+ verifyRequestSent(this);
2656
+ verifyHeadersReceived(this);
2657
+ verifyResponseBodyType(body);
2658
+
2659
+ var chunkSize = this.chunkSize || 10;
2660
+ var index = 0;
2661
+ this.responseText = "";
2662
+
2663
+ do {
2664
+ if (this.async) {
2665
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
2666
+ }
2667
+
2668
+ this.responseText += body.substring(index, index + chunkSize);
2669
+ index += chunkSize;
2670
+ } while (index < body.length);
2671
+
2672
+ var type = this.getResponseHeader("Content-Type");
2673
+
2674
+ if (this.responseText &&
2675
+ (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
2676
+ try {
2677
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
2678
+ } catch (e) {
2679
+ // Unable to parse XML - no biggie
2680
+ }
2681
+ }
2682
+
2683
+ if (this.async) {
2684
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
2685
+ } else {
2686
+ this.readyState = FakeXMLHttpRequest.DONE;
2687
+ }
2688
+ },
2689
+
2690
+ respond: function respond(status, headers, body) {
2691
+ this.setResponseHeaders(headers || {});
2692
+ this.status = typeof status == "number" ? status : 200;
2693
+ this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
2694
+ this.setResponseBody(body || "");
2695
+ }
2696
+ });
2697
+
2698
+ sinon.extend(FakeXMLHttpRequest, {
2699
+ UNSENT: 0,
2700
+ OPENED: 1,
2701
+ HEADERS_RECEIVED: 2,
2702
+ LOADING: 3,
2703
+ DONE: 4
2704
+ });
2705
+
2706
+ // Borrowed from JSpec
2707
+ FakeXMLHttpRequest.parseXML = function parseXML(text) {
2708
+ var xmlDoc;
2709
+
2710
+ if (typeof DOMParser != "undefined") {
2711
+ var parser = new DOMParser();
2712
+ xmlDoc = parser.parseFromString(text, "text/xml");
2713
+ } else {
2714
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
2715
+ xmlDoc.async = "false";
2716
+ xmlDoc.loadXML(text);
2717
+ }
2718
+
2719
+ return xmlDoc;
2720
+ };
2721
+
2722
+ FakeXMLHttpRequest.statusCodes = {
2723
+ 100: "Continue",
2724
+ 101: "Switching Protocols",
2725
+ 200: "OK",
2726
+ 201: "Created",
2727
+ 202: "Accepted",
2728
+ 203: "Non-Authoritative Information",
2729
+ 204: "No Content",
2730
+ 205: "Reset Content",
2731
+ 206: "Partial Content",
2732
+ 300: "Multiple Choice",
2733
+ 301: "Moved Permanently",
2734
+ 302: "Found",
2735
+ 303: "See Other",
2736
+ 304: "Not Modified",
2737
+ 305: "Use Proxy",
2738
+ 307: "Temporary Redirect",
2739
+ 400: "Bad Request",
2740
+ 401: "Unauthorized",
2741
+ 402: "Payment Required",
2742
+ 403: "Forbidden",
2743
+ 404: "Not Found",
2744
+ 405: "Method Not Allowed",
2745
+ 406: "Not Acceptable",
2746
+ 407: "Proxy Authentication Required",
2747
+ 408: "Request Timeout",
2748
+ 409: "Conflict",
2749
+ 410: "Gone",
2750
+ 411: "Length Required",
2751
+ 412: "Precondition Failed",
2752
+ 413: "Request Entity Too Large",
2753
+ 414: "Request-URI Too Long",
2754
+ 415: "Unsupported Media Type",
2755
+ 416: "Requested Range Not Satisfiable",
2756
+ 417: "Expectation Failed",
2757
+ 422: "Unprocessable Entity",
2758
+ 500: "Internal Server Error",
2759
+ 501: "Not Implemented",
2760
+ 502: "Bad Gateway",
2761
+ 503: "Service Unavailable",
2762
+ 504: "Gateway Timeout",
2763
+ 505: "HTTP Version Not Supported"
2764
+ };
2765
+
2766
+ sinon.useFakeXMLHttpRequest = function () {
2767
+ sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
2768
+ if (xhr.supportsXHR) {
2769
+ global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
2770
+ }
2771
+
2772
+ if (xhr.supportsActiveX) {
2773
+ global.ActiveXObject = xhr.GlobalActiveXObject;
2774
+ }
2775
+
2776
+ delete sinon.FakeXMLHttpRequest.restore;
2777
+
2778
+ if (keepOnCreate !== true) {
2779
+ delete sinon.FakeXMLHttpRequest.onCreate;
2780
+ }
2781
+ };
2782
+ if (xhr.supportsXHR) {
2783
+ global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
2784
+ }
2785
+
2786
+ if (xhr.supportsActiveX) {
2787
+ global.ActiveXObject = function ActiveXObject(objId) {
2788
+ if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
2789
+
2790
+ return new sinon.FakeXMLHttpRequest();
2791
+ }
2792
+
2793
+ return new xhr.GlobalActiveXObject(objId);
2794
+ };
2795
+ }
2796
+
2797
+ return sinon.FakeXMLHttpRequest;
2798
+ };
2799
+
2800
+ sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
2801
+ })(this);
2802
+
2803
+ if (typeof module == "object" && typeof require == "function") {
2804
+ module.exports = sinon;
2805
+ }
2806
+
2807
+ /**
2808
+ * @depend fake_xml_http_request.js
2809
+ */
2810
+ /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
2811
+ /*global module, require, window*/
2812
+ /**
2813
+ * The Sinon "server" mimics a web server that receives requests from
2814
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
2815
+ * both synchronously and asynchronously. To respond synchronuously, canned
2816
+ * answers have to be provided upfront.
2817
+ *
2818
+ * @author Christian Johansen (christian@cjohansen.no)
2819
+ * @license BSD
2820
+ *
2821
+ * Copyright (c) 2010-2011 Christian Johansen
2822
+ */
2823
+
2824
+ if (typeof sinon == "undefined") {
2825
+ var sinon = {};
2826
+ }
2827
+
2828
+ sinon.fakeServer = (function () {
2829
+ var push = [].push;
2830
+ function F() {}
2831
+
2832
+ function create(proto) {
2833
+ F.prototype = proto;
2834
+ return new F();
2835
+ }
2836
+
2837
+ function responseArray(handler) {
2838
+ var response = handler;
2839
+
2840
+ if (Object.prototype.toString.call(handler) != "[object Array]") {
2841
+ response = [200, {}, handler];
2842
+ }
2843
+
2844
+ if (typeof response[2] != "string") {
2845
+ throw new TypeError("Fake server response body should be string, but was " +
2846
+ typeof response[2]);
2847
+ }
2848
+
2849
+ return response;
2850
+ }
2851
+
2852
+ var wloc = window.location;
2853
+ var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
2854
+
2855
+ function matchOne(response, reqMethod, reqUrl) {
2856
+ var rmeth = response.method;
2857
+ var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
2858
+ var url = response.url;
2859
+ var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
2860
+
2861
+ return matchMethod && matchUrl;
2862
+ }
2863
+
2864
+ function match(response, request) {
2865
+ var requestMethod = this.getHTTPMethod(request);
2866
+ var requestUrl = request.url;
2867
+
2868
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
2869
+ requestUrl = requestUrl.replace(rCurrLoc, "");
2870
+ }
2871
+
2872
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
2873
+ if (typeof response.response == "function") {
2874
+ var ru = response.url;
2875
+ var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
2876
+ return response.response.apply(response, args);
2877
+ }
2878
+
2879
+ return true;
2880
+ }
2881
+
2882
+ return false;
2883
+ }
2884
+
2885
+ return {
2886
+ create: function () {
2887
+ var server = create(this);
2888
+ this.xhr = sinon.useFakeXMLHttpRequest();
2889
+ server.requests = [];
2890
+
2891
+ this.xhr.onCreate = function (xhrObj) {
2892
+ server.addRequest(xhrObj);
2893
+ };
2894
+
2895
+ return server;
2896
+ },
2897
+
2898
+ addRequest: function addRequest(xhrObj) {
2899
+ var server = this;
2900
+ push.call(this.requests, xhrObj);
2901
+
2902
+ xhrObj.onSend = function () {
2903
+ server.handleRequest(this);
2904
+ };
2905
+
2906
+ if (this.autoRespond && !this.responding) {
2907
+ setTimeout(function () {
2908
+ server.responding = false;
2909
+ server.respond();
2910
+ }, this.autoRespondAfter || 10);
2911
+
2912
+ this.responding = true;
2913
+ }
2914
+ },
2915
+
2916
+ getHTTPMethod: function getHTTPMethod(request) {
2917
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
2918
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
2919
+ return !!matches ? matches[1] : request.method;
2920
+ }
2921
+
2922
+ return request.method;
2923
+ },
2924
+
2925
+ handleRequest: function handleRequest(xhr) {
2926
+ if (xhr.async) {
2927
+ if (!this.queue) {
2928
+ this.queue = [];
2929
+ }
2930
+
2931
+ push.call(this.queue, xhr);
2932
+ } else {
2933
+ this.processRequest(xhr);
2934
+ }
2935
+ },
2936
+
2937
+ respondWith: function respondWith(method, url, body) {
2938
+ if (arguments.length == 1 && typeof method != "function") {
2939
+ this.response = responseArray(method);
2940
+ return;
2941
+ }
2942
+
2943
+ if (!this.responses) { this.responses = []; }
2944
+
2945
+ if (arguments.length == 1) {
2946
+ body = method;
2947
+ url = method = null;
2948
+ }
2949
+
2950
+ if (arguments.length == 2) {
2951
+ body = url;
2952
+ url = method;
2953
+ method = null;
2954
+ }
2955
+
2956
+ push.call(this.responses, {
2957
+ method: method,
2958
+ url: url,
2959
+ response: typeof body == "function" ? body : responseArray(body)
2960
+ });
2961
+ },
2962
+
2963
+ respond: function respond() {
2964
+ if (arguments.length > 0) this.respondWith.apply(this, arguments);
2965
+ var queue = this.queue || [];
2966
+ var request;
2967
+
2968
+ while(request = queue.shift()) {
2969
+ this.processRequest(request);
2970
+ }
2971
+ },
2972
+
2973
+ processRequest: function processRequest(request) {
2974
+ try {
2975
+ if (request.aborted) {
2976
+ return;
2977
+ }
2978
+
2979
+ var response = this.response || [404, {}, ""];
2980
+
2981
+ if (this.responses) {
2982
+ for (var i = 0, l = this.responses.length; i < l; i++) {
2983
+ if (match.call(this, this.responses[i], request)) {
2984
+ response = this.responses[i].response;
2985
+ break;
2986
+ }
2987
+ }
2988
+ }
2989
+
2990
+ if (request.readyState != 4) {
2991
+ request.respond(response[0], response[1], response[2]);
2992
+ }
2993
+ } catch (e) {
2994
+ sinon.logError("Fake server request processing", e);
2995
+ }
2996
+ },
2997
+
2998
+ restore: function restore() {
2999
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
3000
+ }
3001
+ };
3002
+ }());
3003
+
3004
+ if (typeof module == "object" && typeof require == "function") {
3005
+ module.exports = sinon;
3006
+ }
3007
+
3008
+ /**
3009
+ * @depend fake_server.js
3010
+ * @depend fake_timers.js
3011
+ */
3012
+ /*jslint browser: true, eqeqeq: false, onevar: false*/
3013
+ /*global sinon*/
3014
+ /**
3015
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
3016
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
3017
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
3018
+ * it polls the object for completion with setInterval. Dispite the direct
3019
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
3020
+ * in any environment where the ajax implementation depends on setInterval or
3021
+ * setTimeout.
3022
+ *
3023
+ * @author Christian Johansen (christian@cjohansen.no)
3024
+ * @license BSD
3025
+ *
3026
+ * Copyright (c) 2010-2011 Christian Johansen
3027
+ */
3028
+
3029
+ (function () {
3030
+ function Server() {}
3031
+ Server.prototype = sinon.fakeServer;
3032
+
3033
+ sinon.fakeServerWithClock = new Server();
3034
+
3035
+ sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
3036
+ if (xhr.async) {
3037
+ if (typeof setTimeout.clock == "object") {
3038
+ this.clock = setTimeout.clock;
3039
+ } else {
3040
+ this.clock = sinon.useFakeTimers();
3041
+ this.resetClock = true;
3042
+ }
3043
+
3044
+ if (!this.longestTimeout) {
3045
+ var clockSetTimeout = this.clock.setTimeout;
3046
+ var clockSetInterval = this.clock.setInterval;
3047
+ var server = this;
3048
+
3049
+ this.clock.setTimeout = function (fn, timeout) {
3050
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
3051
+
3052
+ return clockSetTimeout.apply(this, arguments);
3053
+ };
3054
+
3055
+ this.clock.setInterval = function (fn, timeout) {
3056
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
3057
+
3058
+ return clockSetInterval.apply(this, arguments);
3059
+ };
3060
+ }
3061
+ }
3062
+
3063
+ return sinon.fakeServer.addRequest.call(this, xhr);
3064
+ };
3065
+
3066
+ sinon.fakeServerWithClock.respond = function respond() {
3067
+ var returnVal = sinon.fakeServer.respond.apply(this, arguments);
3068
+
3069
+ if (this.clock) {
3070
+ this.clock.tick(this.longestTimeout || 0);
3071
+ this.longestTimeout = 0;
3072
+
3073
+ if (this.resetClock) {
3074
+ this.clock.restore();
3075
+ this.resetClock = false;
3076
+ }
3077
+ }
3078
+
3079
+ return returnVal;
3080
+ };
3081
+
3082
+ sinon.fakeServerWithClock.restore = function restore() {
3083
+ if (this.clock) {
3084
+ this.clock.restore();
3085
+ }
3086
+
3087
+ return sinon.fakeServer.restore.apply(this, arguments);
3088
+ };
3089
+ }());
3090
+
3091
+ /**
3092
+ * @depend ../sinon.js
3093
+ * @depend collection.js
3094
+ * @depend util/fake_timers.js
3095
+ * @depend util/fake_server_with_clock.js
3096
+ */
3097
+ /*jslint eqeqeq: false, onevar: false, plusplus: false*/
3098
+ /*global require, module*/
3099
+ /**
3100
+ * Manages fake collections as well as fake utilities such as Sinon's
3101
+ * timers and fake XHR implementation in one convenient object.
3102
+ *
3103
+ * @author Christian Johansen (christian@cjohansen.no)
3104
+ * @license BSD
3105
+ *
3106
+ * Copyright (c) 2010-2011 Christian Johansen
3107
+ */
3108
+
3109
+ if (typeof module == "object" && typeof require == "function") {
3110
+ var sinon = require("../sinon");
3111
+ sinon.extend(sinon, require("./util/fake_timers"));
3112
+ }
3113
+
3114
+ (function () {
3115
+ var push = [].push;
3116
+
3117
+ function exposeValue(sandbox, config, key, value) {
3118
+ if (!value) {
3119
+ return;
3120
+ }
3121
+
3122
+ if (config.injectInto) {
3123
+ config.injectInto[key] = value;
3124
+ } else {
3125
+ push.call(sandbox.args, value);
3126
+ }
3127
+ }
3128
+
3129
+ function prepareSandboxFromConfig(config) {
3130
+ var sandbox = sinon.create(sinon.sandbox);
3131
+
3132
+ if (config.useFakeServer) {
3133
+ if (typeof config.useFakeServer == "object") {
3134
+ sandbox.serverPrototype = config.useFakeServer;
3135
+ }
3136
+
3137
+ sandbox.useFakeServer();
3138
+ }
3139
+
3140
+ if (config.useFakeTimers) {
3141
+ if (typeof config.useFakeTimers == "object") {
3142
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
3143
+ } else {
3144
+ sandbox.useFakeTimers();
3145
+ }
3146
+ }
3147
+
3148
+ return sandbox;
3149
+ }
3150
+
3151
+ sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
3152
+ useFakeTimers: function useFakeTimers() {
3153
+ this.clock = sinon.useFakeTimers.apply(sinon, arguments);
3154
+
3155
+ return this.add(this.clock);
3156
+ },
3157
+
3158
+ serverPrototype: sinon.fakeServer,
3159
+
3160
+ useFakeServer: function useFakeServer() {
3161
+ var proto = this.serverPrototype || sinon.fakeServer;
3162
+
3163
+ if (!proto || !proto.create) {
3164
+ return null;
3165
+ }
3166
+
3167
+ this.server = proto.create();
3168
+ return this.add(this.server);
3169
+ },
3170
+
3171
+ inject: function (obj) {
3172
+ sinon.collection.inject.call(this, obj);
3173
+
3174
+ if (this.clock) {
3175
+ obj.clock = this.clock;
3176
+ }
3177
+
3178
+ if (this.server) {
3179
+ obj.server = this.server;
3180
+ obj.requests = this.server.requests;
3181
+ }
3182
+
3183
+ return obj;
3184
+ },
3185
+
3186
+ create: function (config) {
3187
+ if (!config) {
3188
+ return sinon.create(sinon.sandbox);
3189
+ }
3190
+
3191
+ var sandbox = prepareSandboxFromConfig(config);
3192
+ sandbox.args = sandbox.args || [];
3193
+ var prop, value, exposed = sandbox.inject({});
3194
+
3195
+ if (config.properties) {
3196
+ for (var i = 0, l = config.properties.length; i < l; i++) {
3197
+ prop = config.properties[i];
3198
+ value = exposed[prop] || prop == "sandbox" && sandbox;
3199
+ exposeValue(sandbox, config, prop, value);
3200
+ }
3201
+ } else {
3202
+ exposeValue(sandbox, config, "sandbox", value);
3203
+ }
3204
+
3205
+ return sandbox;
3206
+ }
3207
+ });
3208
+
3209
+ sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
3210
+
3211
+ if (typeof module == "object" && typeof require == "function") {
3212
+ module.exports = sinon.sandbox;
3213
+ }
3214
+ }());
3215
+
3216
+ /**
3217
+ * @depend ../sinon.js
3218
+ * @depend stub.js
3219
+ * @depend mock.js
3220
+ * @depend sandbox.js
3221
+ */
3222
+ /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
3223
+ /*global module, require, sinon*/
3224
+ /**
3225
+ * Test function, sandboxes fakes
3226
+ *
3227
+ * @author Christian Johansen (christian@cjohansen.no)
3228
+ * @license BSD
3229
+ *
3230
+ * Copyright (c) 2010-2011 Christian Johansen
3231
+ */
3232
+
3233
+ (function (sinon) {
3234
+ var commonJSModule = typeof module == "object" && typeof require == "function";
3235
+
3236
+ if (!sinon && commonJSModule) {
3237
+ sinon = require("../sinon");
3238
+ }
3239
+
3240
+ if (!sinon) {
3241
+ return;
3242
+ }
3243
+
3244
+ function test(callback) {
3245
+ var type = typeof callback;
3246
+
3247
+ if (type != "function") {
3248
+ throw new TypeError("sinon.test needs to wrap a test function, got " + type);
3249
+ }
3250
+
3251
+ return function () {
3252
+ var config = sinon.getConfig(sinon.config);
3253
+ config.injectInto = config.injectIntoThis && this || config.injectInto;
3254
+ var sandbox = sinon.sandbox.create(config);
3255
+ var exception, result;
3256
+ var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
3257
+
3258
+ try {
3259
+ result = callback.apply(this, args);
3260
+ } finally {
3261
+ sandbox.verifyAndRestore();
3262
+ }
3263
+
3264
+ return result;
3265
+ };
3266
+ }
3267
+
3268
+ test.config = {
3269
+ injectIntoThis: true,
3270
+ injectInto: null,
3271
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
3272
+ useFakeTimers: true,
3273
+ useFakeServer: true
3274
+ };
3275
+
3276
+ if (commonJSModule) {
3277
+ module.exports = test;
3278
+ } else {
3279
+ sinon.test = test;
3280
+ }
3281
+ }(typeof sinon == "object" && sinon || null));
3282
+
3283
+ /**
3284
+ * @depend ../sinon.js
3285
+ * @depend test.js
3286
+ */
3287
+ /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
3288
+ /*global module, require, sinon*/
3289
+ /**
3290
+ * Test case, sandboxes all test functions
3291
+ *
3292
+ * @author Christian Johansen (christian@cjohansen.no)
3293
+ * @license BSD
3294
+ *
3295
+ * Copyright (c) 2010-2011 Christian Johansen
3296
+ */
3297
+
3298
+ (function (sinon) {
3299
+ var commonJSModule = typeof module == "object" && typeof require == "function";
3300
+
3301
+ if (!sinon && commonJSModule) {
3302
+ sinon = require("../sinon");
3303
+ }
3304
+
3305
+ if (!sinon || !Object.prototype.hasOwnProperty) {
3306
+ return;
3307
+ }
3308
+
3309
+ function createTest(property, setUp, tearDown) {
3310
+ return function () {
3311
+ if (setUp) {
3312
+ setUp.apply(this, arguments);
3313
+ }
3314
+
3315
+ var exception, result;
3316
+
3317
+ try {
3318
+ result = property.apply(this, arguments);
3319
+ } catch (e) {
3320
+ exception = e;
3321
+ }
3322
+
3323
+ if (tearDown) {
3324
+ tearDown.apply(this, arguments);
3325
+ }
3326
+
3327
+ if (exception) {
3328
+ throw exception;
3329
+ }
3330
+
3331
+ return result;
3332
+ };
3333
+ }
3334
+
3335
+ function testCase(tests, prefix) {
3336
+ /*jsl:ignore*/
3337
+ if (!tests || typeof tests != "object") {
3338
+ throw new TypeError("sinon.testCase needs an object with test functions");
3339
+ }
3340
+ /*jsl:end*/
3341
+
3342
+ prefix = prefix || "test";
3343
+ var rPrefix = new RegExp("^" + prefix);
3344
+ var methods = {}, testName, property, method;
3345
+ var setUp = tests.setUp;
3346
+ var tearDown = tests.tearDown;
3347
+
3348
+ for (testName in tests) {
3349
+ if (tests.hasOwnProperty(testName)) {
3350
+ property = tests[testName];
3351
+
3352
+ if (/^(setUp|tearDown)$/.test(testName)) {
3353
+ continue;
3354
+ }
3355
+
3356
+ if (typeof property == "function" && rPrefix.test(testName)) {
3357
+ method = property;
3358
+
3359
+ if (setUp || tearDown) {
3360
+ method = createTest(property, setUp, tearDown);
3361
+ }
3362
+
3363
+ methods[testName] = sinon.test(method);
3364
+ } else {
3365
+ methods[testName] = tests[testName];
3366
+ }
3367
+ }
3368
+ }
3369
+
3370
+ return methods;
3371
+ }
3372
+
3373
+ if (commonJSModule) {
3374
+ module.exports = testCase;
3375
+ } else {
3376
+ sinon.testCase = testCase;
3377
+ }
3378
+ }(typeof sinon == "object" && sinon || null));
3379
+
3380
+ /**
3381
+ * @depend ../sinon.js
3382
+ * @depend stub.js
3383
+ */
3384
+ /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
3385
+ /*global module, require, sinon*/
3386
+ /**
3387
+ * Assertions matching the test spy retrieval interface.
3388
+ *
3389
+ * @author Christian Johansen (christian@cjohansen.no)
3390
+ * @license BSD
3391
+ *
3392
+ * Copyright (c) 2010-2011 Christian Johansen
3393
+ */
3394
+
3395
+ (function (sinon, global) {
3396
+ var commonJSModule = typeof module == "object" && typeof require == "function";
3397
+ var slice = Array.prototype.slice;
3398
+ var assert;
3399
+
3400
+ if (!sinon && commonJSModule) {
3401
+ sinon = require("../sinon");
3402
+ }
3403
+
3404
+ if (!sinon) {
3405
+ return;
3406
+ }
3407
+
3408
+ function verifyIsStub() {
3409
+ var method;
3410
+
3411
+ for (var i = 0, l = arguments.length; i < l; ++i) {
3412
+ method = arguments[i];
3413
+
3414
+ if (!method) {
3415
+ assert.fail("fake is not a spy");
3416
+ }
3417
+
3418
+ if (typeof method != "function") {
3419
+ assert.fail(method + " is not a function");
3420
+ }
3421
+
3422
+ if (typeof method.getCall != "function") {
3423
+ assert.fail(method + " is not stubbed");
3424
+ }
3425
+ }
3426
+ }
3427
+
3428
+ function failAssertion(object, msg) {
3429
+ object = object || global;
3430
+ var failMethod = object.fail || assert.fail;
3431
+ failMethod.call(object, msg);
3432
+ }
3433
+
3434
+ function mirrorPropAsAssertion(name, method, message) {
3435
+ if (arguments.length == 2) {
3436
+ message = method;
3437
+ method = name;
3438
+ }
3439
+
3440
+ assert[name] = function (fake) {
3441
+ verifyIsStub(fake);
3442
+
3443
+ var args = slice.call(arguments, 1);
3444
+ var failed = false;
3445
+
3446
+ if (typeof method == "function") {
3447
+ failed = !method(fake);
3448
+ } else {
3449
+ failed = typeof fake[method] == "function" ?
3450
+ !fake[method].apply(fake, args) : !fake[method];
3451
+ }
3452
+
3453
+ if (failed) {
3454
+ failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
3455
+ } else {
3456
+ assert.pass(name);
3457
+ }
3458
+ };
3459
+ }
3460
+
3461
+ function exposedName(prefix, prop) {
3462
+ return !prefix || /^fail/.test(prop) ? prop :
3463
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
3464
+ };
3465
+
3466
+ assert = {
3467
+ failException: "AssertError",
3468
+
3469
+ fail: function fail(message) {
3470
+ var error = new Error(message);
3471
+ error.name = this.failException || assert.failException;
3472
+
3473
+ throw error;
3474
+ },
3475
+
3476
+ pass: function pass(assertion) {},
3477
+
3478
+ callOrder: function assertCallOrder() {
3479
+ verifyIsStub.apply(null, arguments);
3480
+ var expected = "", actual = "";
3481
+
3482
+ if (!sinon.calledInOrder(arguments)) {
3483
+ try {
3484
+ expected = [].join.call(arguments, ", ");
3485
+ actual = sinon.orderByFirstCall(slice.call(arguments)).join(", ");
3486
+ } catch (e) {
3487
+ // If this fails, we'll just fall back to the blank string
3488
+ }
3489
+
3490
+ failAssertion(this, "expected " + expected + " to be " +
3491
+ "called in order but were called as " + actual);
3492
+ } else {
3493
+ assert.pass("callOrder");
3494
+ }
3495
+ },
3496
+
3497
+ callCount: function assertCallCount(method, count) {
3498
+ verifyIsStub(method);
3499
+
3500
+ if (method.callCount != count) {
3501
+ var msg = "expected %n to be called " + sinon.timesInWords(count) +
3502
+ " but was called %c%C";
3503
+ failAssertion(this, method.printf(msg));
3504
+ } else {
3505
+ assert.pass("callCount");
3506
+ }
3507
+ },
3508
+
3509
+ expose: function expose(target, options) {
3510
+ if (!target) {
3511
+ throw new TypeError("target is null or undefined");
3512
+ }
3513
+
3514
+ var o = options || {};
3515
+ var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
3516
+ var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
3517
+
3518
+ for (var method in this) {
3519
+ if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
3520
+ target[exposedName(prefix, method)] = this[method];
3521
+ }
3522
+ }
3523
+
3524
+ return target;
3525
+ }
3526
+ };
3527
+
3528
+ mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
3529
+ mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
3530
+ "expected %n to not have been called but was called %c%C");
3531
+ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
3532
+ mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
3533
+ mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
3534
+ mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
3535
+ mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
3536
+ mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
3537
+ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
3538
+ mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
3539
+ mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
3540
+ mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
3541
+ mirrorPropAsAssertion("threw", "%n did not throw exception%C");
3542
+ mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
3543
+
3544
+ if (commonJSModule) {
3545
+ module.exports = assert;
3546
+ } else {
3547
+ sinon.assert = assert;
3548
+ }
3549
+ }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global));
3550
+
3551
+ return sinon;}.call(typeof window != 'undefined' && window || {}));