teaspoon 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +382 -260
  3. data/app/assets/javascripts/teaspoon-angular.js +108 -26241
  4. data/app/assets/javascripts/teaspoon-jasmine.js +103 -2642
  5. data/app/assets/javascripts/teaspoon-mocha.js +109 -5416
  6. data/app/assets/javascripts/teaspoon-qunit.js +107 -2255
  7. data/app/assets/javascripts/teaspoon-teaspoon.js +0 -1
  8. data/app/assets/javascripts/teaspoon/angular.coffee +3 -1
  9. data/app/assets/javascripts/teaspoon/base/hook.coffee +21 -0
  10. data/app/assets/javascripts/teaspoon/base/reporters/html.coffee +26 -14
  11. data/app/assets/javascripts/teaspoon/base/reporters/html/progress_view.coffee +1 -1
  12. data/app/assets/javascripts/teaspoon/base/reporters/html/template.coffee +3 -3
  13. data/app/assets/javascripts/teaspoon/base/teaspoon.coffee +10 -1
  14. data/app/assets/javascripts/teaspoon/jasmine.coffee +3 -1
  15. data/app/assets/javascripts/teaspoon/mocha.coffee +3 -1
  16. data/app/assets/javascripts/teaspoon/mocha/reporters/html.coffee +1 -1
  17. data/app/assets/javascripts/teaspoon/qunit.coffee +3 -1
  18. data/app/assets/javascripts/teaspoon/qunit/reporters/html.coffee +1 -1
  19. data/app/assets/javascripts/teaspoon/teaspoon.coffee +0 -1
  20. data/app/assets/stylesheets/teaspoon.css +12 -8
  21. data/app/controllers/teaspoon/suite_controller.rb +32 -0
  22. data/app/views/teaspoon/suite/_body.html.erb +0 -0
  23. data/app/views/teaspoon/suite/_boot.html.erb +4 -0
  24. data/app/views/teaspoon/suite/_boot_require_js.html.erb +19 -0
  25. data/app/views/teaspoon/{spec/suites.html.erb → suite/index.html.erb} +6 -7
  26. data/app/views/teaspoon/suite/show.html.erb +19 -0
  27. data/bin/teaspoon +1 -1
  28. data/config/routes.rb +14 -4
  29. data/lib/generators/teaspoon/install/POST_INSTALL +2 -2
  30. data/lib/generators/teaspoon/install/install_generator.rb +22 -11
  31. data/lib/generators/teaspoon/install/templates/_body.html.erb +0 -0
  32. data/lib/generators/teaspoon/install/templates/_boot.html.erb +4 -0
  33. data/lib/generators/teaspoon/install/templates/jasmine/env.rb +11 -0
  34. data/lib/generators/teaspoon/install/templates/jasmine/env_comments.rb +182 -0
  35. data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.coffee +8 -6
  36. data/lib/generators/teaspoon/install/templates/jasmine/spec_helper.js +8 -7
  37. data/lib/generators/teaspoon/install/templates/mocha/env.rb +11 -0
  38. data/lib/generators/teaspoon/install/templates/mocha/env_comments.rb +182 -0
  39. data/lib/generators/teaspoon/install/templates/mocha/spec_helper.coffee +13 -13
  40. data/lib/generators/teaspoon/install/templates/mocha/spec_helper.js +13 -13
  41. data/lib/generators/teaspoon/install/templates/qunit/env.rb +11 -0
  42. data/lib/generators/teaspoon/install/templates/qunit/env_comments.rb +182 -0
  43. data/lib/generators/teaspoon/install/templates/qunit/test_helper.coffee +6 -5
  44. data/lib/generators/teaspoon/install/templates/qunit/test_helper.js +6 -5
  45. data/lib/tasks/teaspoon.rake +9 -2
  46. data/lib/teaspoon.rb +4 -6
  47. data/lib/teaspoon/command_line.rb +116 -134
  48. data/lib/teaspoon/configuration.rb +144 -66
  49. data/lib/teaspoon/console.rb +70 -37
  50. data/lib/teaspoon/coverage.rb +42 -15
  51. data/lib/teaspoon/deprecated.rb +65 -0
  52. data/lib/teaspoon/drivers/base.rb +10 -0
  53. data/lib/teaspoon/drivers/phantomjs/runner.js +9 -11
  54. data/lib/teaspoon/drivers/phantomjs_driver.rb +21 -21
  55. data/lib/teaspoon/drivers/selenium_driver.rb +32 -13
  56. data/lib/teaspoon/engine.rb +32 -12
  57. data/lib/teaspoon/environment.rb +16 -12
  58. data/lib/teaspoon/exceptions.rb +41 -5
  59. data/lib/teaspoon/exporter.rb +52 -0
  60. data/lib/teaspoon/formatters/base.rb +171 -0
  61. data/lib/teaspoon/formatters/clean_formatter.rb +2 -4
  62. data/lib/teaspoon/formatters/documentation_formatter.rb +60 -0
  63. data/lib/teaspoon/formatters/dot_formatter.rb +12 -90
  64. data/lib/teaspoon/formatters/json_formatter.rb +36 -0
  65. data/lib/teaspoon/formatters/junit_formatter.rb +51 -32
  66. data/lib/teaspoon/formatters/modules/report_module.rb +76 -0
  67. data/lib/teaspoon/formatters/pride_formatter.rb +23 -27
  68. data/lib/teaspoon/formatters/snowday_formatter.rb +7 -11
  69. data/lib/teaspoon/formatters/swayze_or_oprah_formatter.rb +88 -64
  70. data/lib/teaspoon/formatters/tap_formatter.rb +18 -27
  71. data/lib/teaspoon/formatters/tap_y_formatter.rb +35 -45
  72. data/lib/teaspoon/formatters/teamcity_formatter.rb +69 -31
  73. data/lib/teaspoon/instrumentation.rb +33 -33
  74. data/lib/teaspoon/result.rb +2 -1
  75. data/lib/teaspoon/runner.rb +40 -28
  76. data/lib/teaspoon/server.rb +23 -25
  77. data/lib/teaspoon/suite.rb +52 -72
  78. data/lib/teaspoon/utility.rb +3 -14
  79. data/lib/teaspoon/version.rb +1 -1
  80. data/spec/dummy/app/assets/javascripts/integration/integration_spec.coffee +3 -0
  81. data/spec/dummy/app/assets/javascripts/integration/spec_helper.coffee +2 -0
  82. data/spec/dummy/config/application.rb +3 -0
  83. data/spec/features/console_reporter_spec.rb +48 -18
  84. data/spec/features/hooks_spec.rb +23 -41
  85. data/spec/features/html_reporter_spec.rb +38 -21
  86. data/spec/features/install_generator_spec.rb +34 -20
  87. data/spec/features/instrumentation_spec.rb +3 -2
  88. data/spec/fixtures/coverage.json +243 -0
  89. data/spec/javascripts/fixtures/_body.html.erb +1 -0
  90. data/spec/javascripts/jasmine_helper.coffee +1 -1
  91. data/spec/javascripts/teaspoon/base/fixture_spec.coffee +4 -4
  92. data/spec/javascripts/teaspoon/base/reporters/html_spec.coffee +9 -10
  93. data/spec/javascripts/teaspoon/mocha/reporters/html_mspec.coffee +0 -6
  94. data/spec/javascripts/teaspoon/phantomjs/runner_spec.coffee +5 -6
  95. data/spec/javascripts/turbolinks_helper.coffee +1 -1
  96. data/spec/spec_helper.rb +3 -4
  97. data/spec/teaspoon/command_line_spec.rb +139 -23
  98. data/spec/teaspoon/configuration_spec.rb +164 -46
  99. data/spec/teaspoon/console_spec.rb +142 -47
  100. data/spec/teaspoon/coverage_spec.rb +98 -28
  101. data/spec/teaspoon/drivers/base_spec.rb +5 -0
  102. data/spec/teaspoon/drivers/phantomjs_driver_spec.rb +32 -14
  103. data/spec/teaspoon/drivers/selenium_driver_spec.rb +32 -24
  104. data/spec/teaspoon/engine_spec.rb +8 -5
  105. data/spec/teaspoon/environment_spec.rb +56 -33
  106. data/spec/teaspoon/exceptions_spec.rb +57 -0
  107. data/spec/teaspoon/exporter_spec.rb +96 -0
  108. data/spec/teaspoon/formatters/base_spec.rb +259 -0
  109. data/spec/teaspoon/formatters/clean_formatter_spec.rb +37 -0
  110. data/spec/teaspoon/formatters/documentation_formatter_spec.rb +127 -0
  111. data/spec/teaspoon/formatters/dot_formatter_spec.rb +52 -56
  112. data/spec/teaspoon/formatters/json_formatter_spec.rb +77 -0
  113. data/spec/teaspoon/formatters/junit_formatter_spec.rb +72 -35
  114. data/spec/teaspoon/formatters/pride_formatter_spec.rb +37 -0
  115. data/spec/teaspoon/formatters/snowday_formatter_spec.rb +35 -0
  116. data/spec/teaspoon/formatters/tap_formatter_spec.rb +29 -81
  117. data/spec/teaspoon/formatters/tap_y_formatter_spec.rb +31 -141
  118. data/spec/teaspoon/formatters/teamcity_formatter_spec.rb +99 -42
  119. data/spec/teaspoon/instrumentation_spec.rb +44 -44
  120. data/spec/teaspoon/result_spec.rb +37 -0
  121. data/spec/teaspoon/runner_spec.rb +70 -59
  122. data/spec/teaspoon/server_spec.rb +34 -52
  123. data/spec/teaspoon/suite_spec.rb +42 -188
  124. data/spec/teaspoon_env.rb +39 -28
  125. data/vendor/assets/javascripts/{angular-scenario-1.0.5.js → angular/1.0.5.js} +0 -0
  126. data/vendor/assets/javascripts/{angular-scenario-1.0.5.MIT-LICENSE → angular/MIT-LICENSE} +0 -0
  127. data/vendor/assets/javascripts/{jasmine-1.3.1.js → jasmine/1.3.1.js} +0 -0
  128. data/vendor/assets/javascripts/jasmine/2.0.0.js +2412 -0
  129. data/vendor/assets/javascripts/{jasmine-1.3.1.MIT.LICENSE → jasmine/MIT.LICENSE} +0 -0
  130. data/vendor/assets/javascripts/{mocha-1.10.0.js → mocha/1.10.0.js} +1 -0
  131. data/vendor/assets/javascripts/mocha/1.17.1.js +5813 -0
  132. data/vendor/assets/javascripts/{mocha-1.10.1.MIT.LICENSE → mocha/MIT.LICENSE} +0 -0
  133. data/vendor/assets/javascripts/{qunit-1.12.0.js → qunit/1.12.0.js} +1 -1
  134. data/vendor/assets/javascripts/qunit/1.14.0.js +2288 -0
  135. data/vendor/assets/javascripts/{qunit-1.12.0.MIT.LICENSE → qunit/MIT.LICENSE} +0 -0
  136. data/vendor/assets/javascripts/support/chai.js +827 -385
  137. data/vendor/assets/javascripts/support/jasmine-jquery-1.7.0.js +720 -0
  138. data/vendor/assets/javascripts/support/jasmine-jquery-2.0.0.js +812 -0
  139. data/vendor/assets/javascripts/support/sinon-chai.js +17 -0
  140. data/vendor/assets/javascripts/support/sinon.js +1138 -643
  141. metadata +57 -36
  142. data/app/controllers/teaspoon/spec_controller.rb +0 -38
  143. data/app/helpers/teaspoon/spec_helper.rb +0 -36
  144. data/app/views/teaspoon/spec/_require_js.html.erb +0 -21
  145. data/app/views/teaspoon/spec/_standard.html.erb +0 -4
  146. data/app/views/teaspoon/spec/runner.html.erb +0 -19
  147. data/lib/generators/teaspoon/install/templates/env.rb +0 -38
  148. data/lib/generators/teaspoon/install/templates/jasmine/initializer.rb +0 -64
  149. data/lib/generators/teaspoon/install/templates/mocha/initializer.rb +0 -64
  150. data/lib/generators/teaspoon/install/templates/qunit/initializer.rb +0 -64
  151. data/lib/teaspoon/check_coverage.rb +0 -33
  152. data/lib/teaspoon/drivers/base_driver.rb +0 -10
  153. data/lib/teaspoon/exception_handling.rb +0 -18
  154. data/lib/teaspoon/formatters/base_formatter.rb +0 -63
  155. data/spec/dummy/config/initializers/teaspoon.rb +0 -41
  156. data/spec/teaspoon/check_coverage_spec.rb +0 -50
  157. data/spec/teaspoon/formatters/base_formatter_spec.rb +0 -45
  158. data/vendor/assets/javascripts/support/chai.MIT.LICENSE +0 -22
  159. data/vendor/assets/javascripts/support/expect.MIT.LICENSE +0 -22
  160. data/vendor/assets/javascripts/support/jasmine-jquery.MIT.LICENSE +0 -20
  161. data/vendor/assets/javascripts/support/jasmine-jquery.js +0 -659
  162. data/vendor/assets/javascripts/support/sinon-chai.MIT-ISH.LICENSE +0 -13
  163. data/vendor/assets/javascripts/support/sinon.BSD.LICENSE +0 -27
@@ -26,6 +26,13 @@
26
26
  typeof putativeSpy.calledWithExactly === "function";
27
27
  }
28
28
 
29
+ function timesInWords(count) {
30
+ return count === 1 ? "once" :
31
+ count === 2 ? "twice" :
32
+ count === 3 ? "thrice" :
33
+ (count || 0) + " times";
34
+ }
35
+
29
36
  function isCall(putativeCall) {
30
37
  return putativeCall && isSpy(putativeCall.proxy);
31
38
  }
@@ -62,6 +69,15 @@
62
69
  });
63
70
  }
64
71
 
72
+ function sinonPropertyAsBooleanMethod(name, action, nonNegatedSuffix) {
73
+ utils.addMethod(chai.Assertion.prototype, name, function (arg) {
74
+ assertCanWorkWith(this);
75
+
76
+ var messages = getMessages(this._obj, action, nonNegatedSuffix, false, [timesInWords(arg)]);
77
+ this.assert(this._obj[name] === arg, messages.affirmative, messages.negative);
78
+ });
79
+ }
80
+
65
81
  function createSinonMethodHandler(sinonName, action, nonNegatedSuffix) {
66
82
  return function () {
67
83
  assertCanWorkWith(this);
@@ -94,6 +110,7 @@
94
110
  });
95
111
 
96
112
  sinonProperty("called", "been called", " at least once, but it was never called");
113
+ sinonPropertyAsBooleanMethod("callCount", "been called exactly %1", ", but it was called %c%C");
97
114
  sinonProperty("calledOnce", "been called exactly once", ", but it was called %c%C");
98
115
  sinonProperty("calledTwice", "been called exactly twice", ", but it was called %c%C");
99
116
  sinonProperty("calledThrice", "been called exactly thrice", ", but it was called %c%C");
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Sinon.JS 1.7.1, 2013/05/07
2
+ * Sinon.JS 1.9.0, 2014/03/05
3
3
  *
4
4
  * @author Christian Johansen (christian@cjohansen.no)
5
5
  * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
6
6
  *
7
7
  * (The BSD License)
8
8
  *
9
- * Copyright (c) 2010-2013, Christian Johansen, christian@cjohansen.no
9
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
10
10
  * All rights reserved.
11
11
  *
12
12
  * Redistribution and use in source and binary forms, with or without modification,
@@ -34,337 +34,497 @@
34
34
  */
35
35
 
36
36
  this.sinon = (function () {
37
- var buster = (function (setTimeout, B) {
38
- var isNode = typeof require == "function" && typeof module == "object";
39
- var div = typeof document != "undefined" && document.createElement("div");
40
- var F = function () {};
41
-
42
- var buster = {
43
- bind: function bind(obj, methOrProp) {
44
- var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp;
45
- var args = Array.prototype.slice.call(arguments, 2);
46
- return function () {
47
- var allArgs = args.concat(Array.prototype.slice.call(arguments));
48
- return method.apply(obj, allArgs);
49
- };
50
- },
37
+ var samsam, formatio;
38
+ function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else { formatio = fn(samsam); } }
39
+ define.amd = true;
40
+ ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
41
+ (typeof module === "object" &&
42
+ function (m) { module.exports = m(); }) || // Node
43
+ function (m) { this.samsam = m(); } // Browser globals
44
+ )(function () {
45
+ var o = Object.prototype;
46
+ var div = typeof document !== "undefined" && document.createElement("div");
47
+
48
+ function isNaN(value) {
49
+ // Unlike global isNaN, this avoids type coercion
50
+ // typeof check avoids IE host object issues, hat tip to
51
+ // lodash
52
+ var val = value; // JsLint thinks value !== value is "weird"
53
+ return typeof value === "number" && value !== val;
54
+ }
51
55
 
52
- partial: function partial(fn) {
53
- var args = [].slice.call(arguments, 1);
54
- return function () {
55
- return fn.apply(this, args.concat([].slice.call(arguments)));
56
- };
57
- },
56
+ function getClass(value) {
57
+ // Returns the internal [[Class]] by calling Object.prototype.toString
58
+ // with the provided value as this. Return value is a string, naming the
59
+ // internal class, e.g. "Array"
60
+ return o.toString.call(value).split(/[ \]]/)[1];
61
+ }
58
62
 
59
- create: function create(object) {
60
- F.prototype = object;
61
- return new F();
62
- },
63
+ /**
64
+ * @name samsam.isArguments
65
+ * @param Object object
66
+ *
67
+ * Returns ``true`` if ``object`` is an ``arguments`` object,
68
+ * ``false`` otherwise.
69
+ */
70
+ function isArguments(object) {
71
+ if (typeof object !== "object" || typeof object.length !== "number" ||
72
+ getClass(object) === "Array") {
73
+ return false;
74
+ }
75
+ if (typeof object.callee == "function") { return true; }
76
+ try {
77
+ object[object.length] = 6;
78
+ delete object[object.length];
79
+ } catch (e) {
80
+ return true;
81
+ }
82
+ return false;
83
+ }
63
84
 
64
- extend: function extend(target) {
65
- if (!target) { return; }
66
- for (var i = 1, l = arguments.length, prop; i < l; ++i) {
67
- for (prop in arguments[i]) {
68
- target[prop] = arguments[i][prop];
69
- }
70
- }
71
- return target;
72
- },
85
+ /**
86
+ * @name samsam.isElement
87
+ * @param Object object
88
+ *
89
+ * Returns ``true`` if ``object`` is a DOM element node. Unlike
90
+ * Underscore.js/lodash, this function will return ``false`` if ``object``
91
+ * is an *element-like* object, i.e. a regular object with a ``nodeType``
92
+ * property that holds the value ``1``.
93
+ */
94
+ function isElement(object) {
95
+ if (!object || object.nodeType !== 1 || !div) { return false; }
96
+ try {
97
+ object.appendChild(div);
98
+ object.removeChild(div);
99
+ } catch (e) {
100
+ return false;
101
+ }
102
+ return true;
103
+ }
73
104
 
74
- nextTick: function nextTick(callback) {
75
- if (typeof process != "undefined" && process.nextTick) {
76
- return process.nextTick(callback);
77
- }
78
- setTimeout(callback, 0);
79
- },
105
+ /**
106
+ * @name samsam.keys
107
+ * @param Object object
108
+ *
109
+ * Return an array of own property names.
110
+ */
111
+ function keys(object) {
112
+ var ks = [], prop;
113
+ for (prop in object) {
114
+ if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
115
+ }
116
+ return ks;
117
+ }
80
118
 
81
- functionName: function functionName(func) {
82
- if (!func) return "";
83
- if (func.displayName) return func.displayName;
84
- if (func.name) return func.name;
85
- var matches = func.toString().match(/function\s+([^\(]+)/m);
86
- return matches && matches[1] || "";
87
- },
119
+ /**
120
+ * @name samsam.isDate
121
+ * @param Object value
122
+ *
123
+ * Returns true if the object is a ``Date``, or *date-like*. Duck typing
124
+ * of date objects work by checking that the object has a ``getTime``
125
+ * function whose return value equals the return value from the object's
126
+ * ``valueOf``.
127
+ */
128
+ function isDate(value) {
129
+ return typeof value.getTime == "function" &&
130
+ value.getTime() == value.valueOf();
131
+ }
88
132
 
89
- isNode: function isNode(obj) {
90
- if (!div) return false;
91
- try {
92
- obj.appendChild(div);
93
- obj.removeChild(div);
94
- } catch (e) {
95
- return false;
96
- }
97
- return true;
98
- },
133
+ /**
134
+ * @name samsam.isNegZero
135
+ * @param Object value
136
+ *
137
+ * Returns ``true`` if ``value`` is ``-0``.
138
+ */
139
+ function isNegZero(value) {
140
+ return value === 0 && 1 / value === -Infinity;
141
+ }
99
142
 
100
- isElement: function isElement(obj) {
101
- return obj && obj.nodeType === 1 && buster.isNode(obj);
102
- },
143
+ /**
144
+ * @name samsam.equal
145
+ * @param Object obj1
146
+ * @param Object obj2
147
+ *
148
+ * Returns ``true`` if two objects are strictly equal. Compared to
149
+ * ``===`` there are two exceptions:
150
+ *
151
+ * - NaN is considered equal to NaN
152
+ * - -0 and +0 are not considered equal
153
+ */
154
+ function identical(obj1, obj2) {
155
+ if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
156
+ return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
157
+ }
158
+ }
103
159
 
104
- isArray: function isArray(arr) {
105
- return Object.prototype.toString.call(arr) == "[object Array]";
106
- },
107
160
 
108
- flatten: function flatten(arr) {
109
- var result = [], arr = arr || [];
110
- for (var i = 0, l = arr.length; i < l; ++i) {
111
- result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]);
112
- }
113
- return result;
114
- },
161
+ /**
162
+ * @name samsam.deepEqual
163
+ * @param Object obj1
164
+ * @param Object obj2
165
+ *
166
+ * Deep equal comparison. Two values are "deep equal" if:
167
+ *
168
+ * - They are equal, according to samsam.identical
169
+ * - They are both date objects representing the same time
170
+ * - They are both arrays containing elements that are all deepEqual
171
+ * - They are objects with the same set of properties, and each property
172
+ * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
173
+ *
174
+ * Supports cyclic objects.
175
+ */
176
+ function deepEqualCyclic(obj1, obj2) {
177
+
178
+ // used for cyclic comparison
179
+ // contain already visited objects
180
+ var objects1 = [],
181
+ objects2 = [],
182
+ // contain pathes (position in the object structure)
183
+ // of the already visited objects
184
+ // indexes same as in objects arrays
185
+ paths1 = [],
186
+ paths2 = [],
187
+ // contains combinations of already compared objects
188
+ // in the manner: { "$1['ref']$2['ref']": true }
189
+ compared = {};
190
+
191
+ /**
192
+ * used to check, if the value of a property is an object
193
+ * (cyclic logic is only needed for objects)
194
+ * only needed for cyclic logic
195
+ */
196
+ function isObject(value) {
197
+
198
+ if (typeof value === 'object' && value !== null &&
199
+ !(value instanceof Boolean) &&
200
+ !(value instanceof Date) &&
201
+ !(value instanceof Number) &&
202
+ !(value instanceof RegExp) &&
203
+ !(value instanceof String)) {
115
204
 
116
- each: function each(arr, callback) {
117
- for (var i = 0, l = arr.length; i < l; ++i) {
118
- callback(arr[i]);
205
+ return true;
119
206
  }
120
- },
121
207
 
122
- map: function map(arr, callback) {
123
- var results = [];
124
- for (var i = 0, l = arr.length; i < l; ++i) {
125
- results.push(callback(arr[i]));
126
- }
127
- return results;
128
- },
208
+ return false;
209
+ }
129
210
 
130
- parallel: function parallel(fns, callback) {
131
- function cb(err, res) {
132
- if (typeof callback == "function") {
133
- callback(err, res);
134
- callback = null;
211
+ /**
212
+ * returns the index of the given object in the
213
+ * given objects array, -1 if not contained
214
+ * only needed for cyclic logic
215
+ */
216
+ function getIndex(objects, obj) {
217
+
218
+ var i;
219
+ for (i = 0; i < objects.length; i++) {
220
+ if (objects[i] === obj) {
221
+ return i;
135
222
  }
136
223
  }
137
- if (fns.length == 0) { return cb(null, []); }
138
- var remaining = fns.length, results = [];
139
- function makeDone(num) {
140
- return function done(err, result) {
141
- if (err) { return cb(err); }
142
- results[num] = result;
143
- if (--remaining == 0) { cb(null, results); }
144
- };
145
- }
146
- for (var i = 0, l = fns.length; i < l; ++i) {
147
- fns[i](makeDone(i));
148
- }
149
- },
150
224
 
151
- series: function series(fns, callback) {
152
- function cb(err, res) {
153
- if (typeof callback == "function") {
154
- callback(err, res);
155
- }
225
+ return -1;
226
+ }
227
+
228
+ // does the recursion for the deep equal check
229
+ return (function deepEqual(obj1, obj2, path1, path2) {
230
+ var type1 = typeof obj1;
231
+ var type2 = typeof obj2;
232
+
233
+ // == null also matches undefined
234
+ if (obj1 === obj2 ||
235
+ isNaN(obj1) || isNaN(obj2) ||
236
+ obj1 == null || obj2 == null ||
237
+ type1 !== "object" || type2 !== "object") {
238
+
239
+ return identical(obj1, obj2);
156
240
  }
157
- var remaining = fns.slice();
158
- var results = [];
159
- function callNext() {
160
- if (remaining.length == 0) return cb(null, results);
161
- var promise = remaining.shift()(next);
162
- if (promise && typeof promise.then == "function") {
163
- promise.then(buster.partial(next, null), next);
241
+
242
+ // Elements are only equal if identical(expected, actual)
243
+ if (isElement(obj1) || isElement(obj2)) { return false; }
244
+
245
+ var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
246
+ if (isDate1 || isDate2) {
247
+ if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
248
+ return false;
164
249
  }
165
250
  }
166
- function next(err, result) {
167
- if (err) return cb(err);
168
- results.push(result);
169
- callNext();
170
- }
171
- callNext();
172
- },
173
251
 
174
- countdown: function countdown(num, done) {
175
- return function () {
176
- if (--num == 0) done();
177
- };
178
- }
179
- };
180
-
181
- if (typeof process === "object" &&
182
- typeof require === "function" && typeof module === "object") {
183
- var crypto = require("crypto");
184
- var path = require("path");
252
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
253
+ if (obj1.toString() !== obj2.toString()) { return false; }
254
+ }
185
255
 
186
- buster.tmpFile = function (fileName) {
187
- var hashed = crypto.createHash("sha1");
188
- hashed.update(fileName);
189
- var tmpfileName = hashed.digest("hex");
256
+ var class1 = getClass(obj1);
257
+ var class2 = getClass(obj2);
258
+ var keys1 = keys(obj1);
259
+ var keys2 = keys(obj2);
190
260
 
191
- if (process.platform == "win32") {
192
- return path.join(process.env["TEMP"], tmpfileName);
261
+ if (isArguments(obj1) || isArguments(obj2)) {
262
+ if (obj1.length !== obj2.length) { return false; }
193
263
  } else {
194
- return path.join("/tmp", tmpfileName);
264
+ if (type1 !== type2 || class1 !== class2 ||
265
+ keys1.length !== keys2.length) {
266
+ return false;
267
+ }
195
268
  }
196
- };
197
- }
198
269
 
199
- if (Array.prototype.some) {
200
- buster.some = function (arr, fn, thisp) {
201
- return arr.some(fn, thisp);
202
- };
203
- } else {
204
- // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
205
- buster.some = function (arr, fun, thisp) {
206
- if (arr == null) { throw new TypeError(); }
207
- arr = Object(arr);
208
- var len = arr.length >>> 0;
209
- if (typeof fun !== "function") { throw new TypeError(); }
210
-
211
- for (var i = 0; i < len; i++) {
212
- if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) {
270
+ var key, i, l,
271
+ // following vars are used for the cyclic logic
272
+ value1, value2,
273
+ isObject1, isObject2,
274
+ index1, index2,
275
+ newPath1, newPath2;
276
+
277
+ for (i = 0, l = keys1.length; i < l; i++) {
278
+ key = keys1[i];
279
+ if (!o.hasOwnProperty.call(obj2, key)) {
280
+ return false;
281
+ }
282
+
283
+ // Start of the cyclic logic
284
+
285
+ value1 = obj1[key];
286
+ value2 = obj2[key];
287
+
288
+ isObject1 = isObject(value1);
289
+ isObject2 = isObject(value2);
290
+
291
+ // determine, if the objects were already visited
292
+ // (it's faster to check for isObject first, than to
293
+ // get -1 from getIndex for non objects)
294
+ index1 = isObject1 ? getIndex(objects1, value1) : -1;
295
+ index2 = isObject2 ? getIndex(objects2, value2) : -1;
296
+
297
+ // determine the new pathes of the objects
298
+ // - for non cyclic objects the current path will be extended
299
+ // by current property name
300
+ // - for cyclic objects the stored path is taken
301
+ newPath1 = index1 !== -1
302
+ ? paths1[index1]
303
+ : path1 + '[' + JSON.stringify(key) + ']';
304
+ newPath2 = index2 !== -1
305
+ ? paths2[index2]
306
+ : path2 + '[' + JSON.stringify(key) + ']';
307
+
308
+ // stop recursion if current objects are already compared
309
+ if (compared[newPath1 + newPath2]) {
213
310
  return true;
214
311
  }
215
- }
216
312
 
217
- return false;
218
- };
219
- }
313
+ // remember the current objects and their pathes
314
+ if (index1 === -1 && isObject1) {
315
+ objects1.push(value1);
316
+ paths1.push(newPath1);
317
+ }
318
+ if (index2 === -1 && isObject2) {
319
+ objects2.push(value2);
320
+ paths2.push(newPath2);
321
+ }
220
322
 
221
- if (Array.prototype.filter) {
222
- buster.filter = function (arr, fn, thisp) {
223
- return arr.filter(fn, thisp);
224
- };
225
- } else {
226
- // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
227
- buster.filter = function (fn, thisp) {
228
- if (this == null) { throw new TypeError(); }
229
-
230
- var t = Object(this);
231
- var len = t.length >>> 0;
232
- if (typeof fn != "function") { throw new TypeError(); }
233
-
234
- var res = [];
235
- for (var i = 0; i < len; i++) {
236
- if (i in t) {
237
- var val = t[i]; // in case fun mutates this
238
- if (fn.call(thisp, val, i, t)) { res.push(val); }
323
+ // remember that the current objects are already compared
324
+ if (isObject1 && isObject2) {
325
+ compared[newPath1 + newPath2] = true;
326
+ }
327
+
328
+ // End of cyclic logic
329
+
330
+ // neither value1 nor value2 is a cycle
331
+ // continue with next level
332
+ if (!deepEqual(value1, value2, newPath1, newPath2)) {
333
+ return false;
239
334
  }
240
335
  }
241
336
 
242
- return res;
243
- };
337
+ return true;
338
+
339
+ }(obj1, obj2, '$1', '$2'));
244
340
  }
245
341
 
246
- if (isNode) {
247
- module.exports = buster;
248
- buster.eventEmitter = require("./buster-event-emitter");
249
- Object.defineProperty(buster, "defineVersionGetter", {
250
- get: function () {
251
- return require("./define-version-getter");
342
+ var match;
343
+
344
+ function arrayContains(array, subset) {
345
+ if (subset.length === 0) { return true; }
346
+ var i, l, j, k;
347
+ for (i = 0, l = array.length; i < l; ++i) {
348
+ if (match(array[i], subset[0])) {
349
+ for (j = 0, k = subset.length; j < k; ++j) {
350
+ if (!match(array[i + j], subset[j])) { return false; }
351
+ }
352
+ return true;
252
353
  }
253
- });
354
+ }
355
+ return false;
254
356
  }
255
357
 
256
- return buster.extend(B || {}, buster);
257
- }(setTimeout, buster));
258
- if (typeof buster === "undefined") {
259
- var buster = {};
260
- }
358
+ /**
359
+ * @name samsam.match
360
+ * @param Object object
361
+ * @param Object matcher
362
+ *
363
+ * Compare arbitrary value ``object`` with matcher.
364
+ */
365
+ match = function match(object, matcher) {
366
+ if (matcher && typeof matcher.test === "function") {
367
+ return matcher.test(object);
368
+ }
261
369
 
262
- if (typeof module === "object" && typeof require === "function") {
263
- buster = require("buster-core");
264
- }
370
+ if (typeof matcher === "function") {
371
+ return matcher(object) === true;
372
+ }
373
+
374
+ if (typeof matcher === "string") {
375
+ matcher = matcher.toLowerCase();
376
+ var notNull = typeof object === "string" || !!object;
377
+ return notNull &&
378
+ (String(object)).toLowerCase().indexOf(matcher) >= 0;
379
+ }
380
+
381
+ if (typeof matcher === "number") {
382
+ return matcher === object;
383
+ }
384
+
385
+ if (typeof matcher === "boolean") {
386
+ return matcher === object;
387
+ }
388
+
389
+ if (getClass(object) === "Array" && getClass(matcher) === "Array") {
390
+ return arrayContains(object, matcher);
391
+ }
392
+
393
+ if (matcher && typeof matcher === "object") {
394
+ var prop;
395
+ for (prop in matcher) {
396
+ if (!match(object[prop], matcher[prop])) {
397
+ return false;
398
+ }
399
+ }
400
+ return true;
401
+ }
265
402
 
266
- buster.format = buster.format || {};
267
- buster.format.excludeConstructors = ["Object", /^.$/];
268
- buster.format.quoteStrings = true;
403
+ throw new Error("Matcher was not a string, a number, a " +
404
+ "function, a boolean or an object");
405
+ };
269
406
 
270
- buster.format.ascii = (function () {
407
+ return {
408
+ isArguments: isArguments,
409
+ isElement: isElement,
410
+ isDate: isDate,
411
+ isNegZero: isNegZero,
412
+ identical: identical,
413
+ deepEqual: deepEqualCyclic,
414
+ match: match,
415
+ keys: keys
416
+ };
417
+ });
418
+ ((typeof define === "function" && define.amd && function (m) {
419
+ define("formatio", ["samsam"], m);
420
+ }) || (typeof module === "object" && function (m) {
421
+ module.exports = m(require("samsam"));
422
+ }) || function (m) { this.formatio = m(this.samsam); }
423
+ )(function (samsam) {
424
+
425
+ var formatio = {
426
+ excludeConstructors: ["Object", /^.$/],
427
+ quoteStrings: true
428
+ };
271
429
 
272
430
  var hasOwn = Object.prototype.hasOwnProperty;
273
431
 
274
432
  var specialObjects = [];
275
- if (typeof global != "undefined") {
276
- specialObjects.push({ obj: global, value: "[object global]" });
433
+ if (typeof global !== "undefined") {
434
+ specialObjects.push({ object: global, value: "[object global]" });
277
435
  }
278
- if (typeof document != "undefined") {
279
- specialObjects.push({ obj: document, value: "[object HTMLDocument]" });
436
+ if (typeof document !== "undefined") {
437
+ specialObjects.push({
438
+ object: document,
439
+ value: "[object HTMLDocument]"
440
+ });
280
441
  }
281
- if (typeof window != "undefined") {
282
- specialObjects.push({ obj: window, value: "[object Window]" });
442
+ if (typeof window !== "undefined") {
443
+ specialObjects.push({ object: window, value: "[object Window]" });
283
444
  }
284
445
 
285
- function keys(object) {
286
- var k = Object.keys && Object.keys(object) || [];
446
+ function functionName(func) {
447
+ if (!func) { return ""; }
448
+ if (func.displayName) { return func.displayName; }
449
+ if (func.name) { return func.name; }
450
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
451
+ return (matches && matches[1]) || "";
452
+ }
287
453
 
288
- if (k.length == 0) {
289
- for (var prop in object) {
290
- if (hasOwn.call(object, prop)) {
291
- k.push(prop);
292
- }
454
+ function constructorName(f, object) {
455
+ var name = functionName(object && object.constructor);
456
+ var excludes = f.excludeConstructors ||
457
+ formatio.excludeConstructors || [];
458
+
459
+ var i, l;
460
+ for (i = 0, l = excludes.length; i < l; ++i) {
461
+ if (typeof excludes[i] === "string" && excludes[i] === name) {
462
+ return "";
463
+ } else if (excludes[i].test && excludes[i].test(name)) {
464
+ return "";
293
465
  }
294
466
  }
295
467
 
296
- return k.sort();
468
+ return name;
297
469
  }
298
470
 
299
471
  function isCircular(object, objects) {
300
- if (typeof object != "object") {
301
- return false;
302
- }
303
-
304
- for (var i = 0, l = objects.length; i < l; ++i) {
305
- if (objects[i] === object) {
306
- return true;
307
- }
472
+ if (typeof object !== "object") { return false; }
473
+ var i, l;
474
+ for (i = 0, l = objects.length; i < l; ++i) {
475
+ if (objects[i] === object) { return true; }
308
476
  }
309
-
310
477
  return false;
311
478
  }
312
479
 
313
- function ascii(object, processed, indent) {
314
- if (typeof object == "string") {
315
- var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings;
480
+ function ascii(f, object, processed, indent) {
481
+ if (typeof object === "string") {
482
+ var qs = f.quoteStrings;
483
+ var quote = typeof qs !== "boolean" || qs;
316
484
  return processed || quote ? '"' + object + '"' : object;
317
485
  }
318
486
 
319
- if (typeof object == "function" && !(object instanceof RegExp)) {
487
+ if (typeof object === "function" && !(object instanceof RegExp)) {
320
488
  return ascii.func(object);
321
489
  }
322
490
 
323
491
  processed = processed || [];
324
492
 
325
- if (isCircular(object, processed)) {
326
- return "[Circular]";
327
- }
493
+ if (isCircular(object, processed)) { return "[Circular]"; }
328
494
 
329
- if (Object.prototype.toString.call(object) == "[object Array]") {
330
- return ascii.array.call(this, object, processed);
495
+ if (Object.prototype.toString.call(object) === "[object Array]") {
496
+ return ascii.array.call(f, object, processed);
331
497
  }
332
498
 
333
- if (!object) {
334
- return "" + object;
335
- }
499
+ if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
500
+ if (samsam.isElement(object)) { return ascii.element(object); }
336
501
 
337
- if (buster.isElement(object)) {
338
- return ascii.element(object);
339
- }
340
-
341
- if (typeof object.toString == "function" &&
502
+ if (typeof object.toString === "function" &&
342
503
  object.toString !== Object.prototype.toString) {
343
504
  return object.toString();
344
505
  }
345
506
 
346
- for (var i = 0, l = specialObjects.length; i < l; i++) {
347
- if (object === specialObjects[i].obj) {
507
+ var i, l;
508
+ for (i = 0, l = specialObjects.length; i < l; i++) {
509
+ if (object === specialObjects[i].object) {
348
510
  return specialObjects[i].value;
349
511
  }
350
512
  }
351
513
 
352
- return ascii.object.call(this, object, processed, indent);
514
+ return ascii.object.call(f, object, processed, indent);
353
515
  }
354
516
 
355
517
  ascii.func = function (func) {
356
- return "function " + buster.functionName(func) + "() {}";
518
+ return "function " + functionName(func) + "() {}";
357
519
  };
358
520
 
359
521
  ascii.array = function (array, processed) {
360
522
  processed = processed || [];
361
523
  processed.push(array);
362
- var pieces = [];
363
-
364
- for (var i = 0, l = array.length; i < l; ++i) {
365
- pieces.push(ascii.call(this, array[i], processed));
524
+ var i, l, pieces = [];
525
+ for (i = 0, l = array.length; i < l; ++i) {
526
+ pieces.push(ascii(this, array[i], processed));
366
527
  }
367
-
368
528
  return "[" + pieces.join(", ") + "]";
369
529
  };
370
530
 
@@ -372,13 +532,9 @@ this.sinon = (function () {
372
532
  processed = processed || [];
373
533
  processed.push(object);
374
534
  indent = indent || 0;
375
- var pieces = [], properties = keys(object), prop, str, obj;
376
- var is = "";
535
+ var pieces = [], properties = samsam.keys(object).sort();
377
536
  var length = 3;
378
-
379
- for (var i = 0, l = indent; i < l; ++i) {
380
- is += " ";
381
- }
537
+ var prop, str, obj, i, l;
382
538
 
383
539
  for (i = 0, l = properties.length; i < l; ++i) {
384
540
  prop = properties[i];
@@ -387,7 +543,7 @@ this.sinon = (function () {
387
543
  if (isCircular(obj, processed)) {
388
544
  str = "[Circular]";
389
545
  } else {
390
- str = ascii.call(this, obj, processed, indent + 2);
546
+ str = ascii(this, obj, processed, indent + 2);
391
547
  }
392
548
 
393
549
  str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
@@ -395,28 +551,28 @@ this.sinon = (function () {
395
551
  pieces.push(str);
396
552
  }
397
553
 
398
- var cons = ascii.constructorName.call(this, object);
399
- var prefix = cons ? "[" + cons + "] " : ""
554
+ var cons = constructorName(this, object);
555
+ var prefix = cons ? "[" + cons + "] " : "";
556
+ var is = "";
557
+ for (i = 0, l = indent; i < l; ++i) { is += " "; }
400
558
 
401
- return (length + indent) > 80 ?
402
- prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" :
403
- prefix + "{ " + pieces.join(", ") + " }";
559
+ if (length + indent > 80) {
560
+ return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
561
+ is + "}";
562
+ }
563
+ return prefix + "{ " + pieces.join(", ") + " }";
404
564
  };
405
565
 
406
566
  ascii.element = function (element) {
407
567
  var tagName = element.tagName.toLowerCase();
408
- var attrs = element.attributes, attribute, pairs = [], attrName;
409
-
410
- for (var i = 0, l = attrs.length; i < l; ++i) {
411
- attribute = attrs.item(i);
412
- attrName = attribute.nodeName.toLowerCase().replace("html:", "");
568
+ var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
413
569
 
414
- if (attrName == "contenteditable" && attribute.nodeValue == "inherit") {
415
- continue;
416
- }
417
-
418
- if (!!attribute.nodeValue) {
419
- pairs.push(attrName + "=\"" + attribute.nodeValue + "\"");
570
+ for (i = 0, l = attrs.length; i < l; ++i) {
571
+ attr = attrs.item(i);
572
+ attrName = attr.nodeName.toLowerCase().replace("html:", "");
573
+ val = attr.nodeValue;
574
+ if (attrName !== "contenteditable" || val !== "inherit") {
575
+ if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
420
576
  }
421
577
  }
422
578
 
@@ -427,32 +583,36 @@ this.sinon = (function () {
427
583
  content = content.substr(0, 20) + "[...]";
428
584
  }
429
585
 
430
- var res = formatted + pairs.join(" ") + ">" + content + "</" + tagName + ">";
586
+ var res = formatted + pairs.join(" ") + ">" + content +
587
+ "</" + tagName + ">";
431
588
 
432
589
  return res.replace(/ contentEditable="inherit"/, "");
433
590
  };
434
591
 
435
- ascii.constructorName = function (object) {
436
- var name = buster.functionName(object && object.constructor);
437
- var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];
438
-
439
- for (var i = 0, l = excludes.length; i < l; ++i) {
440
- if (typeof excludes[i] == "string" && excludes[i] == name) {
441
- return "";
442
- } else if (excludes[i].test && excludes[i].test(name)) {
443
- return "";
444
- }
592
+ function Formatio(options) {
593
+ for (var opt in options) {
594
+ this[opt] = options[opt];
445
595
  }
596
+ }
446
597
 
447
- return name;
448
- };
598
+ Formatio.prototype = {
599
+ functionName: functionName,
449
600
 
450
- return ascii;
451
- }());
601
+ configure: function (options) {
602
+ return new Formatio(options);
603
+ },
452
604
 
453
- if (typeof module != "undefined") {
454
- module.exports = buster.format;
455
- }
605
+ constructorName: function (object) {
606
+ return constructorName(this, object);
607
+ },
608
+
609
+ ascii: function (object, processed, indent) {
610
+ return ascii(this, object, processed, indent);
611
+ }
612
+ };
613
+
614
+ return Formatio.prototype;
615
+ });
456
616
  /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
457
617
  /*global module, require, __dirname, document*/
458
618
  /**
@@ -464,7 +624,7 @@ this.sinon = (function () {
464
624
  * Copyright (c) 2010-2013 Christian Johansen
465
625
  */
466
626
 
467
- var sinon = (function (buster) {
627
+ var sinon = (function (formatio) {
468
628
  var div = typeof document != "undefined" && document.createElement("div");
469
629
  var hasOwn = Object.prototype.hasOwnProperty;
470
630
 
@@ -517,26 +677,38 @@ this.sinon = (function () {
517
677
  throw new TypeError("Method wrapper should be function");
518
678
  }
519
679
 
520
- var wrappedMethod = object[property];
680
+ var wrappedMethod = object[property],
681
+ error;
521
682
 
522
683
  if (!isFunction(wrappedMethod)) {
523
- throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
684
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
524
685
  property + " as function");
525
686
  }
526
687
 
527
688
  if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
528
- throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
689
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
529
690
  }
530
691
 
531
692
  if (wrappedMethod.calledBefore) {
532
693
  var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
533
- throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
694
+ error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
695
+ }
696
+
697
+ if (error) {
698
+ if (wrappedMethod._stack) {
699
+ error.stack += '\n--------------\n' + wrappedMethod._stack;
700
+ }
701
+ throw error;
534
702
  }
535
703
 
536
- // IE 8 does not support hasOwnProperty on the window object.
537
- var owned = hasOwn.call(object, property);
704
+ // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
705
+ // when using hasOwn.call on objects from other frames.
706
+ var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
538
707
  object[property] = method;
539
708
  method.displayName = property;
709
+ // Set up a stack trace which can be used later to find what line of
710
+ // code the original method was created on.
711
+ method._stack = (new Error('Stack Trace for original')).stack;
540
712
 
541
713
  method.restore = function () {
542
714
  // For prototype properties try to reset by delete first.
@@ -600,27 +772,26 @@ this.sinon = (function () {
600
772
  return false;
601
773
  }
602
774
 
775
+ if (a instanceof RegExp && b instanceof RegExp) {
776
+ return (a.source === b.source) && (a.global === b.global) &&
777
+ (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
778
+ }
779
+
603
780
  var aString = Object.prototype.toString.call(a);
604
781
  if (aString != Object.prototype.toString.call(b)) {
605
782
  return false;
606
783
  }
607
784
 
608
- if (aString == "[object Array]") {
609
- if (a.length !== b.length) {
610
- return false;
611
- }
612
-
613
- for (var i = 0, l = a.length; i < l; i += 1) {
614
- if (!deepEqual(a[i], b[i])) {
615
- return false;
616
- }
617
- }
618
-
619
- return true;
785
+ if (aString == "[object Date]") {
786
+ return a.valueOf() === b.valueOf();
620
787
  }
621
788
 
622
789
  var prop, aLength = 0, bLength = 0;
623
790
 
791
+ if (aString == "[object Array]" && a.length !== b.length) {
792
+ return false;
793
+ }
794
+
624
795
  for (prop in a) {
625
796
  aLength += 1;
626
797
 
@@ -727,7 +898,7 @@ this.sinon = (function () {
727
898
  log: function () {},
728
899
 
729
900
  logError: function (label, err) {
730
- var msg = label + " threw exception: "
901
+ var msg = label + " threw exception: ";
731
902
  sinon.log(msg + "[" + err.name + "] " + err.message);
732
903
  if (err.stack) { sinon.log(err.stack); }
733
904
 
@@ -769,15 +940,21 @@ this.sinon = (function () {
769
940
  }
770
941
  };
771
942
 
772
- var isNode = typeof module == "object" && typeof require == "function";
943
+ var isNode = typeof module !== "undefined" && module.exports;
944
+ var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
773
945
 
774
- if (isNode) {
946
+ if (isAMD) {
947
+ define(function(){
948
+ return sinon;
949
+ });
950
+ } else if (isNode) {
775
951
  try {
776
- buster = { format: require("buster-format") };
952
+ formatio = require("formatio");
777
953
  } catch (e) {}
778
954
  module.exports = sinon;
779
955
  module.exports.spy = require("./sinon/spy");
780
956
  module.exports.spyCall = require("./sinon/call");
957
+ module.exports.behavior = require("./sinon/behavior");
781
958
  module.exports.stub = require("./sinon/stub");
782
959
  module.exports.mock = require("./sinon/mock");
783
960
  module.exports.collection = require("./sinon/collection");
@@ -789,9 +966,8 @@ this.sinon = (function () {
789
966
  module.exports.match = require("./sinon/match");
790
967
  }
791
968
 
792
- if (buster) {
793
- var formatter = sinon.create(buster.format);
794
- formatter.quoteStrings = false;
969
+ if (formatio) {
970
+ var formatter = formatio.configure({ quoteStrings: false });
795
971
  sinon.format = function () {
796
972
  return formatter.ascii.apply(formatter, arguments);
797
973
  };
@@ -808,7 +984,7 @@ this.sinon = (function () {
808
984
  }
809
985
 
810
986
  return sinon;
811
- }(typeof buster == "object" && buster));
987
+ }(typeof formatio == "object" && formatio));
812
988
 
813
989
  /* @depend ../sinon.js */
814
990
  /*jslint eqeqeq: false, onevar: false, plusplus: false*/
@@ -823,7 +999,7 @@ this.sinon = (function () {
823
999
  */
824
1000
 
825
1001
  (function (sinon) {
826
- var commonJSModule = typeof module == "object" && typeof require == "function";
1002
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
827
1003
 
828
1004
  if (!sinon && commonJSModule) {
829
1005
  sinon = require("../sinon");
@@ -876,8 +1052,10 @@ this.sinon = (function () {
876
1052
  }
877
1053
 
878
1054
  matcher.or = function (m2) {
879
- if (!isMatcher(m2)) {
1055
+ if (!arguments.length) {
880
1056
  throw new TypeError("Matcher expected");
1057
+ } else if (!isMatcher(m2)) {
1058
+ m2 = match(m2);
881
1059
  }
882
1060
  var m1 = this;
883
1061
  var or = sinon.create(matcher);
@@ -889,8 +1067,10 @@ this.sinon = (function () {
889
1067
  };
890
1068
 
891
1069
  matcher.and = function (m2) {
892
- if (!isMatcher(m2)) {
1070
+ if (!arguments.length) {
893
1071
  throw new TypeError("Matcher expected");
1072
+ } else if (!isMatcher(m2)) {
1073
+ m2 = match(m2);
894
1074
  }
895
1075
  var m1 = this;
896
1076
  var and = sinon.create(matcher);
@@ -1067,7 +1247,7 @@ this.sinon = (function () {
1067
1247
  */
1068
1248
 
1069
1249
  (function (sinon) {
1070
- var commonJSModule = typeof module == "object" && typeof require == "function";
1250
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
1071
1251
  if (!sinon && commonJSModule) {
1072
1252
  sinon = require("../sinon");
1073
1253
  }
@@ -1140,8 +1320,8 @@ this.sinon = (function () {
1140
1320
  return this.exception === error || this.exception.name === error;
1141
1321
  },
1142
1322
 
1143
- calledWithNew: function calledWithNew(thisValue) {
1144
- return this.thisValue instanceof this.proxy;
1323
+ calledWithNew: function calledWithNew() {
1324
+ return this.proxy.prototype && this.thisValue instanceof this.proxy;
1145
1325
  },
1146
1326
 
1147
1327
  calledBefore: function (other) {
@@ -1241,7 +1421,7 @@ this.sinon = (function () {
1241
1421
  proxyCall.callId = id;
1242
1422
 
1243
1423
  return proxyCall;
1244
- };
1424
+ }
1245
1425
  createSpyCall.toString = callProto.toString; // used by mocks
1246
1426
 
1247
1427
  if (commonJSModule) {
@@ -1268,7 +1448,7 @@ this.sinon = (function () {
1268
1448
  */
1269
1449
 
1270
1450
  (function (sinon) {
1271
- var commonJSModule = typeof module == "object" && typeof require == "function";
1451
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
1272
1452
  var push = Array.prototype.push;
1273
1453
  var slice = Array.prototype.slice;
1274
1454
  var callId = 0;
@@ -1299,8 +1479,6 @@ this.sinon = (function () {
1299
1479
  return;
1300
1480
  }
1301
1481
 
1302
- var alen = args.length;
1303
-
1304
1482
  for (var i = 0, l = fakes.length; i < l; i++) {
1305
1483
  if (fakes[i].matches(args, strict)) {
1306
1484
  return fakes[i];
@@ -1407,18 +1585,24 @@ this.sinon = (function () {
1407
1585
  } else {
1408
1586
  returnValue = (this.func || func).apply(thisValue, args);
1409
1587
  }
1588
+
1589
+ var thisCall = this.getCall(this.callCount - 1);
1590
+ if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
1591
+ returnValue = thisValue;
1592
+ }
1410
1593
  } catch (e) {
1411
- push.call(this.returnValues, undefined);
1412
1594
  exception = e;
1413
- throw e;
1414
- } finally {
1415
- push.call(this.exceptions, exception);
1416
1595
  }
1417
1596
 
1597
+ push.call(this.exceptions, exception);
1418
1598
  push.call(this.returnValues, returnValue);
1419
1599
 
1420
1600
  createCallProperties.call(this);
1421
1601
 
1602
+ if (exception !== undefined) {
1603
+ throw exception;
1604
+ }
1605
+
1422
1606
  return returnValue;
1423
1607
  },
1424
1608
 
@@ -1432,6 +1616,17 @@ this.sinon = (function () {
1432
1616
  this.callIds[i]);
1433
1617
  },
1434
1618
 
1619
+ getCalls: function () {
1620
+ var calls = [];
1621
+ var i;
1622
+
1623
+ for (i = 0; i < this.callCount; i++) {
1624
+ calls.push(this.getCall(i));
1625
+ }
1626
+
1627
+ return calls;
1628
+ },
1629
+
1435
1630
  calledBefore: function calledBefore(spyFn) {
1436
1631
  if (!this.called) {
1437
1632
  return false;
@@ -1468,6 +1663,7 @@ this.sinon = (function () {
1468
1663
  var original = this;
1469
1664
  var fake = this._create();
1470
1665
  fake.matchingAguments = args;
1666
+ fake.parent = this;
1471
1667
  push.call(this.fakes, fake);
1472
1668
 
1473
1669
  fake.withArgs = function () {
@@ -1508,7 +1704,7 @@ this.sinon = (function () {
1508
1704
 
1509
1705
  if (typeof formatter == "function") {
1510
1706
  return formatter.call(null, spy, args);
1511
- } else if (!isNaN(parseInt(specifyer), 10)) {
1707
+ } else if (!isNaN(parseInt(specifyer, 10))) {
1512
1708
  return sinon.format(args[specifyer - 1]);
1513
1709
  }
1514
1710
 
@@ -1608,44 +1804,376 @@ this.sinon = (function () {
1608
1804
  push.call(calls, stringifiedCall);
1609
1805
  }
1610
1806
 
1611
- return calls.length > 0 ? "\n" + calls.join("\n") : "";
1807
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
1808
+ },
1809
+
1810
+ "t": function (spy) {
1811
+ var objects = [];
1812
+
1813
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
1814
+ push.call(objects, sinon.format(spy.thisValues[i]));
1815
+ }
1816
+
1817
+ return objects.join(", ");
1818
+ },
1819
+
1820
+ "*": function (spy, args) {
1821
+ var formatted = [];
1822
+
1823
+ for (var i = 0, l = args.length; i < l; ++i) {
1824
+ push.call(formatted, sinon.format(args[i]));
1825
+ }
1826
+
1827
+ return formatted.join(", ");
1828
+ }
1829
+ };
1830
+
1831
+ sinon.extend(spy, spyApi);
1832
+
1833
+ spy.spyCall = sinon.spyCall;
1834
+
1835
+ if (commonJSModule) {
1836
+ module.exports = spy;
1837
+ } else {
1838
+ sinon.spy = spy;
1839
+ }
1840
+ }(typeof sinon == "object" && sinon || null));
1841
+
1842
+ /**
1843
+ * @depend ../sinon.js
1844
+ */
1845
+ /*jslint eqeqeq: false, onevar: false*/
1846
+ /*global module, require, sinon, process, setImmediate, setTimeout*/
1847
+ /**
1848
+ * Stub behavior
1849
+ *
1850
+ * @author Christian Johansen (christian@cjohansen.no)
1851
+ * @author Tim Fischbach (mail@timfischbach.de)
1852
+ * @license BSD
1853
+ *
1854
+ * Copyright (c) 2010-2013 Christian Johansen
1855
+ */
1856
+
1857
+ (function (sinon) {
1858
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
1859
+
1860
+ if (!sinon && commonJSModule) {
1861
+ sinon = require("../sinon");
1862
+ }
1863
+
1864
+ if (!sinon) {
1865
+ return;
1866
+ }
1867
+
1868
+ var slice = Array.prototype.slice;
1869
+ var join = Array.prototype.join;
1870
+ var proto;
1871
+
1872
+ var nextTick = (function () {
1873
+ if (typeof process === "object" && typeof process.nextTick === "function") {
1874
+ return process.nextTick;
1875
+ } else if (typeof setImmediate === "function") {
1876
+ return setImmediate;
1877
+ } else {
1878
+ return function (callback) {
1879
+ setTimeout(callback, 0);
1880
+ };
1881
+ }
1882
+ })();
1883
+
1884
+ function throwsException(error, message) {
1885
+ if (typeof error == "string") {
1886
+ this.exception = new Error(message || "");
1887
+ this.exception.name = error;
1888
+ } else if (!error) {
1889
+ this.exception = new Error("Error");
1890
+ } else {
1891
+ this.exception = error;
1892
+ }
1893
+
1894
+ return this;
1895
+ }
1896
+
1897
+ function getCallback(behavior, args) {
1898
+ var callArgAt = behavior.callArgAt;
1899
+
1900
+ if (callArgAt < 0) {
1901
+ var callArgProp = behavior.callArgProp;
1902
+
1903
+ for (var i = 0, l = args.length; i < l; ++i) {
1904
+ if (!callArgProp && typeof args[i] == "function") {
1905
+ return args[i];
1906
+ }
1907
+
1908
+ if (callArgProp && args[i] &&
1909
+ typeof args[i][callArgProp] == "function") {
1910
+ return args[i][callArgProp];
1911
+ }
1912
+ }
1913
+
1914
+ return null;
1915
+ }
1916
+
1917
+ return args[callArgAt];
1918
+ }
1919
+
1920
+ function getCallbackError(behavior, func, args) {
1921
+ if (behavior.callArgAt < 0) {
1922
+ var msg;
1923
+
1924
+ if (behavior.callArgProp) {
1925
+ msg = sinon.functionName(behavior.stub) +
1926
+ " expected to yield to '" + behavior.callArgProp +
1927
+ "', but no object with such a property was passed.";
1928
+ } else {
1929
+ msg = sinon.functionName(behavior.stub) +
1930
+ " expected to yield, but no callback was passed.";
1931
+ }
1932
+
1933
+ if (args.length > 0) {
1934
+ msg += " Received [" + join.call(args, ", ") + "]";
1935
+ }
1936
+
1937
+ return msg;
1938
+ }
1939
+
1940
+ return "argument at index " + behavior.callArgAt + " is not a function: " + func;
1941
+ }
1942
+
1943
+ function callCallback(behavior, args) {
1944
+ if (typeof behavior.callArgAt == "number") {
1945
+ var func = getCallback(behavior, args);
1946
+
1947
+ if (typeof func != "function") {
1948
+ throw new TypeError(getCallbackError(behavior, func, args));
1949
+ }
1950
+
1951
+ if (behavior.callbackAsync) {
1952
+ nextTick(function() {
1953
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
1954
+ });
1955
+ } else {
1956
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
1957
+ }
1958
+ }
1959
+ }
1960
+
1961
+ proto = {
1962
+ create: function(stub) {
1963
+ var behavior = sinon.extend({}, sinon.behavior);
1964
+ delete behavior.create;
1965
+ behavior.stub = stub;
1966
+
1967
+ return behavior;
1968
+ },
1969
+
1970
+ isPresent: function() {
1971
+ return (typeof this.callArgAt == 'number' ||
1972
+ this.exception ||
1973
+ typeof this.returnArgAt == 'number' ||
1974
+ this.returnThis ||
1975
+ this.returnValueDefined);
1976
+ },
1977
+
1978
+ invoke: function(context, args) {
1979
+ callCallback(this, args);
1980
+
1981
+ if (this.exception) {
1982
+ throw this.exception;
1983
+ } else if (typeof this.returnArgAt == 'number') {
1984
+ return args[this.returnArgAt];
1985
+ } else if (this.returnThis) {
1986
+ return context;
1987
+ }
1988
+
1989
+ return this.returnValue;
1990
+ },
1991
+
1992
+ onCall: function(index) {
1993
+ return this.stub.onCall(index);
1994
+ },
1995
+
1996
+ onFirstCall: function() {
1997
+ return this.stub.onFirstCall();
1998
+ },
1999
+
2000
+ onSecondCall: function() {
2001
+ return this.stub.onSecondCall();
2002
+ },
2003
+
2004
+ onThirdCall: function() {
2005
+ return this.stub.onThirdCall();
2006
+ },
2007
+
2008
+ withArgs: function(/* arguments */) {
2009
+ throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
2010
+ 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
2011
+ },
2012
+
2013
+ callsArg: function callsArg(pos) {
2014
+ if (typeof pos != "number") {
2015
+ throw new TypeError("argument index is not number");
2016
+ }
2017
+
2018
+ this.callArgAt = pos;
2019
+ this.callbackArguments = [];
2020
+ this.callbackContext = undefined;
2021
+ this.callArgProp = undefined;
2022
+ this.callbackAsync = false;
2023
+
2024
+ return this;
2025
+ },
2026
+
2027
+ callsArgOn: function callsArgOn(pos, context) {
2028
+ if (typeof pos != "number") {
2029
+ throw new TypeError("argument index is not number");
2030
+ }
2031
+ if (typeof context != "object") {
2032
+ throw new TypeError("argument context is not an object");
2033
+ }
2034
+
2035
+ this.callArgAt = pos;
2036
+ this.callbackArguments = [];
2037
+ this.callbackContext = context;
2038
+ this.callArgProp = undefined;
2039
+ this.callbackAsync = false;
2040
+
2041
+ return this;
2042
+ },
2043
+
2044
+ callsArgWith: function callsArgWith(pos) {
2045
+ if (typeof pos != "number") {
2046
+ throw new TypeError("argument index is not number");
2047
+ }
2048
+
2049
+ this.callArgAt = pos;
2050
+ this.callbackArguments = slice.call(arguments, 1);
2051
+ this.callbackContext = undefined;
2052
+ this.callArgProp = undefined;
2053
+ this.callbackAsync = false;
2054
+
2055
+ return this;
2056
+ },
2057
+
2058
+ callsArgOnWith: function callsArgWith(pos, context) {
2059
+ if (typeof pos != "number") {
2060
+ throw new TypeError("argument index is not number");
2061
+ }
2062
+ if (typeof context != "object") {
2063
+ throw new TypeError("argument context is not an object");
2064
+ }
2065
+
2066
+ this.callArgAt = pos;
2067
+ this.callbackArguments = slice.call(arguments, 2);
2068
+ this.callbackContext = context;
2069
+ this.callArgProp = undefined;
2070
+ this.callbackAsync = false;
2071
+
2072
+ return this;
2073
+ },
2074
+
2075
+ yields: function () {
2076
+ this.callArgAt = -1;
2077
+ this.callbackArguments = slice.call(arguments, 0);
2078
+ this.callbackContext = undefined;
2079
+ this.callArgProp = undefined;
2080
+ this.callbackAsync = false;
2081
+
2082
+ return this;
2083
+ },
2084
+
2085
+ yieldsOn: function (context) {
2086
+ if (typeof context != "object") {
2087
+ throw new TypeError("argument context is not an object");
2088
+ }
2089
+
2090
+ this.callArgAt = -1;
2091
+ this.callbackArguments = slice.call(arguments, 1);
2092
+ this.callbackContext = context;
2093
+ this.callArgProp = undefined;
2094
+ this.callbackAsync = false;
2095
+
2096
+ return this;
2097
+ },
2098
+
2099
+ yieldsTo: function (prop) {
2100
+ this.callArgAt = -1;
2101
+ this.callbackArguments = slice.call(arguments, 1);
2102
+ this.callbackContext = undefined;
2103
+ this.callArgProp = prop;
2104
+ this.callbackAsync = false;
2105
+
2106
+ return this;
2107
+ },
2108
+
2109
+ yieldsToOn: function (prop, context) {
2110
+ if (typeof context != "object") {
2111
+ throw new TypeError("argument context is not an object");
2112
+ }
2113
+
2114
+ this.callArgAt = -1;
2115
+ this.callbackArguments = slice.call(arguments, 2);
2116
+ this.callbackContext = context;
2117
+ this.callArgProp = prop;
2118
+ this.callbackAsync = false;
2119
+
2120
+ return this;
1612
2121
  },
1613
2122
 
1614
- "t": function (spy) {
1615
- var objects = [];
1616
2123
 
1617
- for (var i = 0, l = spy.callCount; i < l; ++i) {
1618
- push.call(objects, sinon.format(spy.thisValues[i]));
1619
- }
2124
+ "throws": throwsException,
2125
+ throwsException: throwsException,
1620
2126
 
1621
- return objects.join(", ");
1622
- },
2127
+ returns: function returns(value) {
2128
+ this.returnValue = value;
2129
+ this.returnValueDefined = true;
1623
2130
 
1624
- "*": function (spy, args) {
1625
- var formatted = [];
2131
+ return this;
2132
+ },
1626
2133
 
1627
- for (var i = 0, l = args.length; i < l; ++i) {
1628
- push.call(formatted, sinon.format(args[i]));
2134
+ returnsArg: function returnsArg(pos) {
2135
+ if (typeof pos != "number") {
2136
+ throw new TypeError("argument index is not number");
1629
2137
  }
1630
2138
 
1631
- return formatted.join(", ");
2139
+ this.returnArgAt = pos;
2140
+
2141
+ return this;
2142
+ },
2143
+
2144
+ returnsThis: function returnsThis() {
2145
+ this.returnThis = true;
2146
+
2147
+ return this;
1632
2148
  }
1633
2149
  };
1634
2150
 
1635
- sinon.extend(spy, spyApi);
1636
-
1637
- spy.spyCall = sinon.spyCall;
2151
+ // create asynchronous versions of callsArg* and yields* methods
2152
+ for (var method in proto) {
2153
+ // need to avoid creating anotherasync versions of the newly added async methods
2154
+ if (proto.hasOwnProperty(method) &&
2155
+ method.match(/^(callsArg|yields)/) &&
2156
+ !method.match(/Async/)) {
2157
+ proto[method + 'Async'] = (function (syncFnName) {
2158
+ return function () {
2159
+ var result = this[syncFnName].apply(this, arguments);
2160
+ this.callbackAsync = true;
2161
+ return result;
2162
+ };
2163
+ })(method);
2164
+ }
2165
+ }
1638
2166
 
1639
2167
  if (commonJSModule) {
1640
- module.exports = spy;
2168
+ module.exports = proto;
1641
2169
  } else {
1642
- sinon.spy = spy;
2170
+ sinon.behavior = proto;
1643
2171
  }
1644
2172
  }(typeof sinon == "object" && sinon || null));
1645
-
1646
2173
  /**
1647
2174
  * @depend ../sinon.js
1648
2175
  * @depend spy.js
2176
+ * @depend behavior.js
1649
2177
  */
1650
2178
  /*jslint eqeqeq: false, onevar: false*/
1651
2179
  /*global module, require, sinon*/
@@ -1659,7 +2187,7 @@ this.sinon = (function () {
1659
2187
  */
1660
2188
 
1661
2189
  (function (sinon) {
1662
- var commonJSModule = typeof module == "object" && typeof require == "function";
2190
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
1663
2191
 
1664
2192
  if (!sinon && commonJSModule) {
1665
2193
  sinon = require("../sinon");
@@ -1682,11 +2210,11 @@ this.sinon = (function () {
1682
2210
  wrapper = stub.create();
1683
2211
  }
1684
2212
 
1685
- if (!object && !property) {
2213
+ if (!object && typeof property === "undefined") {
1686
2214
  return sinon.stub.create();
1687
2215
  }
1688
2216
 
1689
- if (!property && !!object && typeof object == "object") {
2217
+ if (typeof property === "undefined" && typeof object == "object") {
1690
2218
  for (var prop in object) {
1691
2219
  if (typeof object[prop] === "function") {
1692
2220
  stub(object, prop);
@@ -1699,128 +2227,26 @@ this.sinon = (function () {
1699
2227
  return sinon.wrapMethod(object, property, wrapper);
1700
2228
  }
1701
2229
 
1702
- function getChangingValue(stub, property) {
1703
- var index = stub.callCount - 1;
1704
- var values = stub[property];
1705
- var prop = index in values ? values[index] : values[values.length - 1];
1706
- stub[property + "Last"] = prop;
1707
-
1708
- return prop;
1709
- }
1710
-
1711
- function getCallback(stub, args) {
1712
- var callArgAt = getChangingValue(stub, "callArgAts");
1713
-
1714
- if (callArgAt < 0) {
1715
- var callArgProp = getChangingValue(stub, "callArgProps");
1716
-
1717
- for (var i = 0, l = args.length; i < l; ++i) {
1718
- if (!callArgProp && typeof args[i] == "function") {
1719
- return args[i];
1720
- }
1721
-
1722
- if (callArgProp && args[i] &&
1723
- typeof args[i][callArgProp] == "function") {
1724
- return args[i][callArgProp];
1725
- }
1726
- }
1727
-
1728
- return null;
1729
- }
1730
-
1731
- return args[callArgAt];
2230
+ function getDefaultBehavior(stub) {
2231
+ return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
1732
2232
  }
1733
2233
 
1734
- var join = Array.prototype.join;
1735
-
1736
- function getCallbackError(stub, func, args) {
1737
- if (stub.callArgAtsLast < 0) {
1738
- var msg;
1739
-
1740
- if (stub.callArgPropsLast) {
1741
- msg = sinon.functionName(stub) +
1742
- " expected to yield to '" + stub.callArgPropsLast +
1743
- "', but no object with such a property was passed."
1744
- } else {
1745
- msg = sinon.functionName(stub) +
1746
- " expected to yield, but no callback was passed."
1747
- }
1748
-
1749
- if (args.length > 0) {
1750
- msg += " Received [" + join.call(args, ", ") + "]";
1751
- }
1752
-
1753
- return msg;
1754
- }
1755
-
1756
- return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
2234
+ function getParentBehaviour(stub) {
2235
+ return (stub.parent && getCurrentBehavior(stub.parent));
1757
2236
  }
1758
2237
 
1759
- var nextTick = (function () {
1760
- if (typeof process === "object" && typeof process.nextTick === "function") {
1761
- return process.nextTick;
1762
- } else if (typeof setImmediate === "function") {
1763
- return setImmediate;
1764
- } else {
1765
- return function (callback) {
1766
- setTimeout(callback, 0);
1767
- };
1768
- }
1769
- })();
1770
-
1771
- function callCallback(stub, args) {
1772
- if (stub.callArgAts.length > 0) {
1773
- var func = getCallback(stub, args);
1774
-
1775
- if (typeof func != "function") {
1776
- throw new TypeError(getCallbackError(stub, func, args));
1777
- }
1778
-
1779
- var callbackArguments = getChangingValue(stub, "callbackArguments");
1780
- var callbackContext = getChangingValue(stub, "callbackContexts");
1781
-
1782
- if (stub.callbackAsync) {
1783
- nextTick(function() {
1784
- func.apply(callbackContext, callbackArguments);
1785
- });
1786
- } else {
1787
- func.apply(callbackContext, callbackArguments);
1788
- }
1789
- }
2238
+ function getCurrentBehavior(stub) {
2239
+ var behavior = stub.behaviors[stub.callCount - 1];
2240
+ return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
1790
2241
  }
1791
2242
 
1792
2243
  var uuid = 0;
1793
2244
 
1794
2245
  sinon.extend(stub, (function () {
1795
- var slice = Array.prototype.slice, proto;
1796
-
1797
- function throwsException(error, message) {
1798
- if (typeof error == "string") {
1799
- this.exception = new Error(message || "");
1800
- this.exception.name = error;
1801
- } else if (!error) {
1802
- this.exception = new Error("Error");
1803
- } else {
1804
- this.exception = error;
1805
- }
1806
-
1807
- return this;
1808
- }
1809
-
1810
- proto = {
2246
+ var proto = {
1811
2247
  create: function create() {
1812
2248
  var functionStub = function () {
1813
-
1814
- callCallback(functionStub, arguments);
1815
-
1816
- if (functionStub.exception) {
1817
- throw functionStub.exception;
1818
- } else if (typeof functionStub.returnArgAt == 'number') {
1819
- return arguments[functionStub.returnArgAt];
1820
- } else if (functionStub.returnThis) {
1821
- return this;
1822
- }
1823
- return functionStub.returnValue;
2249
+ return getCurrentBehavior(functionStub).invoke(this, arguments);
1824
2250
  };
1825
2251
 
1826
2252
  functionStub.id = "stub#" + uuid++;
@@ -1828,26 +2254,22 @@ this.sinon = (function () {
1828
2254
  functionStub = sinon.spy.create(functionStub);
1829
2255
  functionStub.func = orig;
1830
2256
 
1831
- functionStub.callArgAts = [];
1832
- functionStub.callbackArguments = [];
1833
- functionStub.callbackContexts = [];
1834
- functionStub.callArgProps = [];
1835
-
1836
2257
  sinon.extend(functionStub, stub);
1837
2258
  functionStub._create = sinon.stub.create;
1838
2259
  functionStub.displayName = "stub";
1839
2260
  functionStub.toString = sinon.functionToString;
1840
2261
 
2262
+ functionStub.defaultBehavior = null;
2263
+ functionStub.behaviors = [];
2264
+
1841
2265
  return functionStub;
1842
2266
  },
1843
2267
 
1844
2268
  resetBehavior: function () {
1845
2269
  var i;
1846
2270
 
1847
- this.callArgAts = [];
1848
- this.callbackArguments = [];
1849
- this.callbackContexts = [];
1850
- this.callArgProps = [];
2271
+ this.defaultBehavior = null;
2272
+ this.behaviors = [];
1851
2273
 
1852
2274
  delete this.returnValue;
1853
2275
  delete this.returnArgAt;
@@ -1860,151 +2282,44 @@ this.sinon = (function () {
1860
2282
  }
1861
2283
  },
1862
2284
 
1863
- returns: function returns(value) {
1864
- this.returnValue = value;
1865
-
1866
- return this;
1867
- },
1868
-
1869
- returnsArg: function returnsArg(pos) {
1870
- if (typeof pos != "number") {
1871
- throw new TypeError("argument index is not number");
1872
- }
1873
-
1874
- this.returnArgAt = pos;
1875
-
1876
- return this;
1877
- },
1878
-
1879
- returnsThis: function returnsThis() {
1880
- this.returnThis = true;
1881
-
1882
- return this;
1883
- },
1884
-
1885
- "throws": throwsException,
1886
- throwsException: throwsException,
1887
-
1888
- callsArg: function callsArg(pos) {
1889
- if (typeof pos != "number") {
1890
- throw new TypeError("argument index is not number");
1891
- }
1892
-
1893
- this.callArgAts.push(pos);
1894
- this.callbackArguments.push([]);
1895
- this.callbackContexts.push(undefined);
1896
- this.callArgProps.push(undefined);
1897
-
1898
- return this;
1899
- },
1900
-
1901
- callsArgOn: function callsArgOn(pos, context) {
1902
- if (typeof pos != "number") {
1903
- throw new TypeError("argument index is not number");
1904
- }
1905
- if (typeof context != "object") {
1906
- throw new TypeError("argument context is not an object");
1907
- }
1908
-
1909
- this.callArgAts.push(pos);
1910
- this.callbackArguments.push([]);
1911
- this.callbackContexts.push(context);
1912
- this.callArgProps.push(undefined);
1913
-
1914
- return this;
1915
- },
1916
-
1917
- callsArgWith: function callsArgWith(pos) {
1918
- if (typeof pos != "number") {
1919
- throw new TypeError("argument index is not number");
1920
- }
1921
-
1922
- this.callArgAts.push(pos);
1923
- this.callbackArguments.push(slice.call(arguments, 1));
1924
- this.callbackContexts.push(undefined);
1925
- this.callArgProps.push(undefined);
1926
-
1927
- return this;
1928
- },
1929
-
1930
- callsArgOnWith: function callsArgWith(pos, context) {
1931
- if (typeof pos != "number") {
1932
- throw new TypeError("argument index is not number");
1933
- }
1934
- if (typeof context != "object") {
1935
- throw new TypeError("argument context is not an object");
2285
+ onCall: function(index) {
2286
+ if (!this.behaviors[index]) {
2287
+ this.behaviors[index] = sinon.behavior.create(this);
1936
2288
  }
1937
2289
 
1938
- this.callArgAts.push(pos);
1939
- this.callbackArguments.push(slice.call(arguments, 2));
1940
- this.callbackContexts.push(context);
1941
- this.callArgProps.push(undefined);
1942
-
1943
- return this;
1944
- },
1945
-
1946
- yields: function () {
1947
- this.callArgAts.push(-1);
1948
- this.callbackArguments.push(slice.call(arguments, 0));
1949
- this.callbackContexts.push(undefined);
1950
- this.callArgProps.push(undefined);
1951
-
1952
- return this;
2290
+ return this.behaviors[index];
1953
2291
  },
1954
2292
 
1955
- yieldsOn: function (context) {
1956
- if (typeof context != "object") {
1957
- throw new TypeError("argument context is not an object");
1958
- }
1959
-
1960
- this.callArgAts.push(-1);
1961
- this.callbackArguments.push(slice.call(arguments, 1));
1962
- this.callbackContexts.push(context);
1963
- this.callArgProps.push(undefined);
1964
-
1965
- return this;
2293
+ onFirstCall: function() {
2294
+ return this.onCall(0);
1966
2295
  },
1967
2296
 
1968
- yieldsTo: function (prop) {
1969
- this.callArgAts.push(-1);
1970
- this.callbackArguments.push(slice.call(arguments, 1));
1971
- this.callbackContexts.push(undefined);
1972
- this.callArgProps.push(prop);
1973
-
1974
- return this;
2297
+ onSecondCall: function() {
2298
+ return this.onCall(1);
1975
2299
  },
1976
2300
 
1977
- yieldsToOn: function (prop, context) {
1978
- if (typeof context != "object") {
1979
- throw new TypeError("argument context is not an object");
1980
- }
1981
-
1982
- this.callArgAts.push(-1);
1983
- this.callbackArguments.push(slice.call(arguments, 2));
1984
- this.callbackContexts.push(context);
1985
- this.callArgProps.push(prop);
1986
-
1987
- return this;
2301
+ onThirdCall: function() {
2302
+ return this.onCall(2);
1988
2303
  }
1989
2304
  };
1990
2305
 
1991
- // create asynchronous versions of callsArg* and yields* methods
1992
- for (var method in proto) {
1993
- // need to avoid creating anotherasync versions of the newly added async methods
1994
- if (proto.hasOwnProperty(method) &&
1995
- method.match(/^(callsArg|yields|thenYields$)/) &&
1996
- !method.match(/Async/)) {
1997
- proto[method + 'Async'] = (function (syncFnName) {
1998
- return function () {
1999
- this.callbackAsync = true;
2000
- return this[syncFnName].apply(this, arguments);
2306
+ for (var method in sinon.behavior) {
2307
+ if (sinon.behavior.hasOwnProperty(method) &&
2308
+ !proto.hasOwnProperty(method) &&
2309
+ method != 'create' &&
2310
+ method != 'withArgs' &&
2311
+ method != 'invoke') {
2312
+ proto[method] = (function(behaviorMethod) {
2313
+ return function() {
2314
+ this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
2315
+ this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
2316
+ return this;
2001
2317
  };
2002
- })(method);
2318
+ }(method));
2003
2319
  }
2004
2320
  }
2005
2321
 
2006
2322
  return proto;
2007
-
2008
2323
  }()));
2009
2324
 
2010
2325
  if (commonJSModule) {
@@ -2030,8 +2345,9 @@ this.sinon = (function () {
2030
2345
  */
2031
2346
 
2032
2347
  (function (sinon) {
2033
- var commonJSModule = typeof module == "object" && typeof require == "function";
2348
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
2034
2349
  var push = [].push;
2350
+ var match;
2035
2351
 
2036
2352
  if (!sinon && commonJSModule) {
2037
2353
  sinon = require("../sinon");
@@ -2041,6 +2357,12 @@ this.sinon = (function () {
2041
2357
  return;
2042
2358
  }
2043
2359
 
2360
+ match = sinon.match;
2361
+
2362
+ if (!match && commonJSModule) {
2363
+ match = require("./match");
2364
+ }
2365
+
2044
2366
  function mock(object) {
2045
2367
  if (!object) {
2046
2368
  return sinon.expectation.create("Anonymous mock");
@@ -2221,6 +2543,14 @@ this.sinon = (function () {
2221
2543
  return expectation.callCount == expectation.maxCalls;
2222
2544
  }
2223
2545
 
2546
+ function verifyMatcher(possibleMatcher, arg){
2547
+ if (match && match.isMatcher(possibleMatcher)) {
2548
+ return possibleMatcher.test(arg);
2549
+ } else {
2550
+ return true;
2551
+ }
2552
+ }
2553
+
2224
2554
  return {
2225
2555
  minCalls: 1,
2226
2556
  maxCalls: 1,
@@ -2330,6 +2660,12 @@ this.sinon = (function () {
2330
2660
  }
2331
2661
 
2332
2662
  for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2663
+
2664
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2665
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2666
+ ", didn't match " + this.expectedArguments.toString());
2667
+ }
2668
+
2333
2669
  if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2334
2670
  sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2335
2671
  ", expected " + sinon.format(this.expectedArguments));
@@ -2362,6 +2698,10 @@ this.sinon = (function () {
2362
2698
  }
2363
2699
 
2364
2700
  for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2701
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2702
+ return false;
2703
+ }
2704
+
2365
2705
  if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
2366
2706
  return false;
2367
2707
  }
@@ -2455,7 +2795,7 @@ this.sinon = (function () {
2455
2795
  */
2456
2796
 
2457
2797
  (function (sinon) {
2458
- var commonJSModule = typeof module == "object" && typeof require == "function";
2798
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
2459
2799
  var push = [].push;
2460
2800
  var hasOwnProperty = Object.prototype.hasOwnProperty;
2461
2801
 
@@ -2623,6 +2963,10 @@ this.sinon = (function () {
2623
2963
  throw new Error("Function requires at least 1 parameter");
2624
2964
  }
2625
2965
 
2966
+ if (typeof args[0] === "undefined") {
2967
+ throw new Error("Callback must be provided to timer calls");
2968
+ }
2969
+
2626
2970
  var toId = id++;
2627
2971
  var delay = args[1] || 0;
2628
2972
 
@@ -2724,6 +3068,16 @@ this.sinon = (function () {
2724
3068
  this.clearTimeout(timerId);
2725
3069
  },
2726
3070
 
3071
+ setImmediate: function setImmediate(callback) {
3072
+ var passThruArgs = Array.prototype.slice.call(arguments, 1);
3073
+
3074
+ return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
3075
+ },
3076
+
3077
+ clearImmediate: function clearImmediate(timerId) {
3078
+ this.clearTimeout(timerId);
3079
+ },
3080
+
2727
3081
  tick: function tick(ms) {
2728
3082
  ms = typeof ms == "number" ? ms : parseTime(ms);
2729
3083
  var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
@@ -2754,7 +3108,7 @@ this.sinon = (function () {
2754
3108
  },
2755
3109
 
2756
3110
  firstTimerInRange: function (from, to) {
2757
- var timer, smallest, originalTimer;
3111
+ var timer, smallest = null, originalTimer;
2758
3112
 
2759
3113
  for (var id in this.timeouts) {
2760
3114
  if (this.timeouts.hasOwnProperty(id)) {
@@ -2762,7 +3116,7 @@ this.sinon = (function () {
2762
3116
  continue;
2763
3117
  }
2764
3118
 
2765
- if (!smallest || this.timeouts[id].callAt < smallest) {
3119
+ if (smallest === null || this.timeouts[id].callAt < smallest) {
2766
3120
  originalTimer = this.timeouts[id];
2767
3121
  smallest = this.timeouts[id].callAt;
2768
3122
 
@@ -2868,21 +3222,39 @@ this.sinon = (function () {
2868
3222
  target.parse = source.parse;
2869
3223
  target.UTC = source.UTC;
2870
3224
  target.prototype.toUTCString = source.prototype.toUTCString;
3225
+
3226
+ for (var prop in source) {
3227
+ if (source.hasOwnProperty(prop)) {
3228
+ target[prop] = source[prop];
3229
+ }
3230
+ }
3231
+
2871
3232
  return target;
2872
3233
  }
2873
3234
 
2874
3235
  var methods = ["Date", "setTimeout", "setInterval",
2875
3236
  "clearTimeout", "clearInterval"];
2876
3237
 
3238
+ if (typeof global.setImmediate !== "undefined") {
3239
+ methods.push("setImmediate");
3240
+ }
3241
+
3242
+ if (typeof global.clearImmediate !== "undefined") {
3243
+ methods.push("clearImmediate");
3244
+ }
3245
+
2877
3246
  function restore() {
2878
3247
  var method;
2879
3248
 
2880
3249
  for (var i = 0, l = this.methods.length; i < l; i++) {
2881
3250
  method = this.methods[i];
3251
+
2882
3252
  if (global[method].hadOwnProperty) {
2883
3253
  global[method] = this["_" + method];
2884
3254
  } else {
2885
- delete global[method];
3255
+ try {
3256
+ delete global[method];
3257
+ } catch (e) {}
2886
3258
  }
2887
3259
  }
2888
3260
 
@@ -2933,12 +3305,14 @@ this.sinon = (function () {
2933
3305
  sinon.timers = {
2934
3306
  setTimeout: setTimeout,
2935
3307
  clearTimeout: clearTimeout,
3308
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
3309
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
2936
3310
  setInterval: setInterval,
2937
3311
  clearInterval: clearInterval,
2938
3312
  Date: Date
2939
3313
  };
2940
3314
 
2941
- if (typeof module == "object" && typeof require == "function") {
3315
+ if (typeof module !== 'undefined' && module.exports) {
2942
3316
  module.exports = sinon;
2943
3317
  }
2944
3318
 
@@ -2983,14 +3357,33 @@ this.sinon = (function () {
2983
3357
  }
2984
3358
  };
2985
3359
 
3360
+ sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
3361
+ this.initEvent(type, false, false, target);
3362
+ this.loaded = progressEventRaw.loaded || null;
3363
+ this.total = progressEventRaw.total || null;
3364
+ };
3365
+
3366
+ sinon.ProgressEvent.prototype = new sinon.Event();
3367
+
3368
+ sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
3369
+
3370
+ sinon.CustomEvent = function CustomEvent(type, customData, target) {
3371
+ this.initEvent(type, false, false, target);
3372
+ this.detail = customData.detail || null;
3373
+ };
3374
+
3375
+ sinon.CustomEvent.prototype = new sinon.Event();
3376
+
3377
+ sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
3378
+
2986
3379
  sinon.EventTarget = {
2987
- addEventListener: function addEventListener(event, listener, useCapture) {
3380
+ addEventListener: function addEventListener(event, listener) {
2988
3381
  this.eventListeners = this.eventListeners || {};
2989
3382
  this.eventListeners[event] = this.eventListeners[event] || [];
2990
3383
  push.call(this.eventListeners[event], listener);
2991
3384
  },
2992
3385
 
2993
- removeEventListener: function removeEventListener(event, listener, useCapture) {
3386
+ removeEventListener: function removeEventListener(event, listener) {
2994
3387
  var listeners = this.eventListeners && this.eventListeners[event] || [];
2995
3388
 
2996
3389
  for (var i = 0, l = listeners.length; i < l; ++i) {
@@ -3032,13 +3425,15 @@ this.sinon = (function () {
3032
3425
  * Copyright (c) 2010-2013 Christian Johansen
3033
3426
  */
3034
3427
 
3035
- if (typeof sinon == "undefined") {
3036
- this.sinon = {};
3037
- }
3038
- sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
3039
-
3040
3428
  // wrapper for global
3041
3429
  (function(global) {
3430
+ if (typeof sinon === "undefined") {
3431
+ global.sinon = {};
3432
+ }
3433
+
3434
+ var supportsProgress = typeof ProgressEvent !== "undefined";
3435
+ var supportsCustomEvent = typeof CustomEvent !== "undefined";
3436
+ sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
3042
3437
  var xhr = sinon.xhr;
3043
3438
  xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
3044
3439
  xhr.GlobalActiveXObject = global.ActiveXObject;
@@ -3046,6 +3441,7 @@ this.sinon = (function () {
3046
3441
  xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
3047
3442
  xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
3048
3443
  ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
3444
+ xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
3049
3445
 
3050
3446
  /*jsl:ignore*/
3051
3447
  var unsafeHeaders = {
@@ -3076,24 +3472,69 @@ this.sinon = (function () {
3076
3472
  this.requestBody = null;
3077
3473
  this.status = 0;
3078
3474
  this.statusText = "";
3475
+ this.upload = new UploadProgress();
3476
+ if (sinon.xhr.supportsCORS) {
3477
+ this.withCredentials = false;
3478
+ }
3479
+
3079
3480
 
3080
3481
  var xhr = this;
3482
+ var events = ["loadstart", "load", "abort", "loadend"];
3081
3483
 
3082
- ["loadstart", "load", "abort", "loadend"].forEach(function (eventName) {
3484
+ function addEventListener(eventName) {
3083
3485
  xhr.addEventListener(eventName, function (event) {
3084
3486
  var listener = xhr["on" + eventName];
3085
3487
 
3086
3488
  if (listener && typeof listener == "function") {
3087
- listener(event);
3489
+ listener.call(this, event);
3088
3490
  }
3089
3491
  });
3090
- });
3492
+ }
3493
+
3494
+ for (var i = events.length - 1; i >= 0; i--) {
3495
+ addEventListener(events[i]);
3496
+ }
3091
3497
 
3092
3498
  if (typeof FakeXMLHttpRequest.onCreate == "function") {
3093
3499
  FakeXMLHttpRequest.onCreate(this);
3094
3500
  }
3095
3501
  }
3096
3502
 
3503
+ // An upload object is created for each
3504
+ // FakeXMLHttpRequest and allows upload
3505
+ // events to be simulated using uploadProgress
3506
+ // and uploadError.
3507
+ function UploadProgress() {
3508
+ this.eventListeners = {
3509
+ "progress": [],
3510
+ "load": [],
3511
+ "abort": [],
3512
+ "error": []
3513
+ }
3514
+ }
3515
+
3516
+ UploadProgress.prototype.addEventListener = function(event, listener) {
3517
+ this.eventListeners[event].push(listener);
3518
+ };
3519
+
3520
+ UploadProgress.prototype.removeEventListener = function(event, listener) {
3521
+ var listeners = this.eventListeners[event] || [];
3522
+
3523
+ for (var i = 0, l = listeners.length; i < l; ++i) {
3524
+ if (listeners[i] == listener) {
3525
+ return listeners.splice(i, 1);
3526
+ }
3527
+ }
3528
+ };
3529
+
3530
+ UploadProgress.prototype.dispatchEvent = function(event) {
3531
+ var listeners = this.eventListeners[event.type] || [];
3532
+
3533
+ for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
3534
+ listener(event);
3535
+ }
3536
+ };
3537
+
3097
3538
  function verifyState(xhr) {
3098
3539
  if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
3099
3540
  throw new Error("INVALID_STATE_ERR");
@@ -3115,7 +3556,7 @@ this.sinon = (function () {
3115
3556
  function some(collection, callback) {
3116
3557
  for (var index = 0; index < collection.length; index++) {
3117
3558
  if(callback(collection[index]) === true) return true;
3118
- };
3559
+ }
3119
3560
  return false;
3120
3561
  }
3121
3562
  // largest arity in XHR is 5 - XHR#open
@@ -3127,7 +3568,7 @@ this.sinon = (function () {
3127
3568
  case 3: return obj[method](args[0],args[1],args[2]);
3128
3569
  case 4: return obj[method](args[0],args[1],args[2],args[3]);
3129
3570
  case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
3130
- };
3571
+ }
3131
3572
  };
3132
3573
 
3133
3574
  FakeXMLHttpRequest.filters = [];
@@ -3166,7 +3607,7 @@ this.sinon = (function () {
3166
3607
  if(xhr.readyState === FakeXMLHttpRequest.DONE) {
3167
3608
  copyAttrs(["responseXML"]);
3168
3609
  }
3169
- if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
3610
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
3170
3611
  };
3171
3612
  if(xhr.addEventListener) {
3172
3613
  for(var event in fakeXhr.eventListeners) {
@@ -3184,6 +3625,12 @@ this.sinon = (function () {
3184
3625
  };
3185
3626
  FakeXMLHttpRequest.useFilters = false;
3186
3627
 
3628
+ function verifyRequestOpened(xhr) {
3629
+ if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
3630
+ throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
3631
+ }
3632
+ }
3633
+
3187
3634
  function verifyRequestSent(xhr) {
3188
3635
  if (xhr.readyState == FakeXMLHttpRequest.DONE) {
3189
3636
  throw new Error("Request done");
@@ -3247,6 +3694,10 @@ this.sinon = (function () {
3247
3694
  case FakeXMLHttpRequest.DONE:
3248
3695
  this.dispatchEvent(new sinon.Event("load", false, false, this));
3249
3696
  this.dispatchEvent(new sinon.Event("loadend", false, false, this));
3697
+ this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
3698
+ if (supportsProgress) {
3699
+ this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
3700
+ }
3250
3701
  break;
3251
3702
  }
3252
3703
  },
@@ -3267,6 +3718,7 @@ this.sinon = (function () {
3267
3718
 
3268
3719
  // Helps testing
3269
3720
  setResponseHeaders: function setResponseHeaders(headers) {
3721
+ verifyRequestOpened(this);
3270
3722
  this.responseHeaders = {};
3271
3723
 
3272
3724
  for (var header in headers) {
@@ -3322,6 +3774,9 @@ this.sinon = (function () {
3322
3774
  this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
3323
3775
 
3324
3776
  this.dispatchEvent(new sinon.Event("abort", false, false, this));
3777
+
3778
+ this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
3779
+
3325
3780
  if (typeof this.onerror === "function") {
3326
3781
  this.onerror();
3327
3782
  }
@@ -3401,14 +3856,22 @@ this.sinon = (function () {
3401
3856
  },
3402
3857
 
3403
3858
  respond: function respond(status, headers, body) {
3404
- this.setResponseHeaders(headers || {});
3405
3859
  this.status = typeof status == "number" ? status : 200;
3406
3860
  this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
3861
+ this.setResponseHeaders(headers || {});
3407
3862
  this.setResponseBody(body || "");
3408
- if (typeof this.onload === "function"){
3409
- this.onload();
3863
+ },
3864
+
3865
+ uploadProgress: function uploadProgress(progressEventRaw) {
3866
+ if (supportsProgress) {
3867
+ this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
3410
3868
  }
3869
+ },
3411
3870
 
3871
+ uploadError: function uploadError(error) {
3872
+ if (supportsCustomEvent) {
3873
+ this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
3874
+ }
3412
3875
  }
3413
3876
  });
3414
3877
 
@@ -3515,9 +3978,10 @@ this.sinon = (function () {
3515
3978
  };
3516
3979
 
3517
3980
  sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
3518
- })(this);
3519
3981
 
3520
- if (typeof module == "object" && typeof require == "function") {
3982
+ })(typeof global === "object" ? global : this);
3983
+
3984
+ if (typeof module !== 'undefined' && module.exports) {
3521
3985
  module.exports = sinon;
3522
3986
  }
3523
3987
 
@@ -3579,7 +4043,6 @@ this.sinon = (function () {
3579
4043
  }
3580
4044
 
3581
4045
  function match(response, request) {
3582
- var requestMethod = this.getHTTPMethod(request);
3583
4046
  var requestUrl = request.url;
3584
4047
 
3585
4048
  if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
@@ -3589,7 +4052,7 @@ this.sinon = (function () {
3589
4052
  if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
3590
4053
  if (typeof response.response == "function") {
3591
4054
  var ru = response.url;
3592
- var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
4055
+ var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
3593
4056
  return response.response.apply(response, args);
3594
4057
  }
3595
4058
 
@@ -3627,16 +4090,16 @@ this.sinon = (function () {
3627
4090
 
3628
4091
  xhrObj.onSend = function () {
3629
4092
  server.handleRequest(this);
3630
- };
3631
4093
 
3632
- if (this.autoRespond && !this.responding) {
3633
- setTimeout(function () {
3634
- server.responding = false;
3635
- server.respond();
3636
- }, this.autoRespondAfter || 10);
4094
+ if (server.autoRespond && !server.responding) {
4095
+ setTimeout(function () {
4096
+ server.responding = false;
4097
+ server.respond();
4098
+ }, server.autoRespondAfter || 10);
3637
4099
 
3638
- this.responding = true;
3639
- }
4100
+ server.responding = true;
4101
+ }
4102
+ };
3640
4103
  },
3641
4104
 
3642
4105
  getHTTPMethod: function getHTTPMethod(request) {
@@ -3689,9 +4152,10 @@ this.sinon = (function () {
3689
4152
  respond: function respond() {
3690
4153
  if (arguments.length > 0) this.respondWith.apply(this, arguments);
3691
4154
  var queue = this.queue || [];
4155
+ var requests = queue.splice(0);
3692
4156
  var request;
3693
4157
 
3694
- while(request = queue.shift()) {
4158
+ while(request = requests.shift()) {
3695
4159
  this.processRequest(request);
3696
4160
  }
3697
4161
  },
@@ -3705,7 +4169,7 @@ this.sinon = (function () {
3705
4169
  var response = this.response || [404, {}, ""];
3706
4170
 
3707
4171
  if (this.responses) {
3708
- for (var i = 0, l = this.responses.length; i < l; i++) {
4172
+ for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
3709
4173
  if (match.call(this, this.responses[i], request)) {
3710
4174
  response = this.responses[i].response;
3711
4175
  break;
@@ -3729,7 +4193,7 @@ this.sinon = (function () {
3729
4193
  };
3730
4194
  }());
3731
4195
 
3732
- if (typeof module == "object" && typeof require == "function") {
4196
+ if (typeof module !== 'undefined' && module.exports) {
3733
4197
  module.exports = sinon;
3734
4198
  }
3735
4199
 
@@ -3834,7 +4298,7 @@ this.sinon = (function () {
3834
4298
  * Copyright (c) 2010-2013 Christian Johansen
3835
4299
  */
3836
4300
 
3837
- if (typeof module == "object" && typeof require == "function") {
4301
+ if (typeof module !== 'undefined' && module.exports) {
3838
4302
  var sinon = require("../sinon");
3839
4303
  sinon.extend(sinon, require("./util/fake_timers"));
3840
4304
  }
@@ -3847,8 +4311,9 @@ this.sinon = (function () {
3847
4311
  return;
3848
4312
  }
3849
4313
 
3850
- if (config.injectInto) {
4314
+ if (config.injectInto && !(key in config.injectInto)) {
3851
4315
  config.injectInto[key] = value;
4316
+ sandbox.injectedKeys.push(key);
3852
4317
  } else {
3853
4318
  push.call(sandbox.args, value);
3854
4319
  }
@@ -3911,6 +4376,20 @@ this.sinon = (function () {
3911
4376
  return obj;
3912
4377
  },
3913
4378
 
4379
+ restore: function () {
4380
+ sinon.collection.restore.apply(this, arguments);
4381
+ this.restoreContext();
4382
+ },
4383
+
4384
+ restoreContext: function () {
4385
+ if (this.injectedKeys) {
4386
+ for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
4387
+ delete this.injectInto[this.injectedKeys[i]];
4388
+ }
4389
+ this.injectedKeys = [];
4390
+ }
4391
+ },
4392
+
3914
4393
  create: function (config) {
3915
4394
  if (!config) {
3916
4395
  return sinon.create(sinon.sandbox);
@@ -3918,6 +4397,8 @@ this.sinon = (function () {
3918
4397
 
3919
4398
  var sandbox = prepareSandboxFromConfig(config);
3920
4399
  sandbox.args = sandbox.args || [];
4400
+ sandbox.injectedKeys = [];
4401
+ sandbox.injectInto = config.injectInto;
3921
4402
  var prop, value, exposed = sandbox.inject({});
3922
4403
 
3923
4404
  if (config.properties) {
@@ -3936,7 +4417,7 @@ this.sinon = (function () {
3936
4417
 
3937
4418
  sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
3938
4419
 
3939
- if (typeof module == "object" && typeof require == "function") {
4420
+ if (typeof module !== 'undefined' && module.exports) {
3940
4421
  module.exports = sinon.sandbox;
3941
4422
  }
3942
4423
  }());
@@ -3959,7 +4440,7 @@ this.sinon = (function () {
3959
4440
  */
3960
4441
 
3961
4442
  (function (sinon) {
3962
- var commonJSModule = typeof module == "object" && typeof require == "function";
4443
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
3963
4444
 
3964
4445
  if (!sinon && commonJSModule) {
3965
4446
  sinon = require("../sinon");
@@ -4032,7 +4513,7 @@ this.sinon = (function () {
4032
4513
  */
4033
4514
 
4034
4515
  (function (sinon) {
4035
- var commonJSModule = typeof module == "object" && typeof require == "function";
4516
+ var commonJSModule = typeof module !== 'undefined' && module.exports;
4036
4517
 
4037
4518
  if (!sinon && commonJSModule) {
4038
4519
  sinon = require("../sinon");
@@ -4129,7 +4610,7 @@ this.sinon = (function () {
4129
4610
  */
4130
4611
 
4131
4612
  (function (sinon, global) {
4132
- var commonJSModule = typeof module == "object" && typeof require == "function";
4613
+ var commonJSModule = typeof module !== "undefined" && module.exports;
4133
4614
  var slice = Array.prototype.slice;
4134
4615
  var assert;
4135
4616
 
@@ -4197,7 +4678,7 @@ this.sinon = (function () {
4197
4678
  function exposedName(prefix, prop) {
4198
4679
  return !prefix || /^fail/.test(prop) ? prop :
4199
4680
  prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
4200
- };
4681
+ }
4201
4682
 
4202
4683
  assert = {
4203
4684
  failException: "AssertError",
@@ -4265,6 +4746,20 @@ this.sinon = (function () {
4265
4746
  }
4266
4747
 
4267
4748
  return target;
4749
+ },
4750
+
4751
+ match: function match(actual, expectation) {
4752
+ var matcher = sinon.match(expectation);
4753
+ if (matcher.test(actual)) {
4754
+ assert.pass("match");
4755
+ } else {
4756
+ var formatted = [
4757
+ "expected value to match",
4758
+ " expected = " + sinon.format(expectation),
4759
+ " actual = " + sinon.format(actual)
4760
+ ]
4761
+ failAssertion(this, formatted.join("\n"));
4762
+ }
4268
4763
  }
4269
4764
  };
4270
4765