konacha-chai-matchers 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -113,29 +113,35 @@
113
113
  });
114
114
 
115
115
  chai.Assertion.addMethod('html', function (html) {
116
+ var actual = flag(this, 'object').html();
116
117
  this.assert(
117
- flag(this, 'object').html() === html
118
- , 'expected #{this} to have HTML #{exp}'
118
+ actual === html
119
+ , 'expected #{this} to have HTML #{exp}, but the HTML was #{act}'
119
120
  , 'expected #{this} not to have HTML #{exp}'
120
121
  , html
122
+ , actual
121
123
  );
122
124
  });
123
125
 
124
126
  chai.Assertion.addMethod('text', function (text) {
127
+ var actual = flag(this, 'object').text();
125
128
  this.assert(
126
- flag(this, 'object').text() === text
127
- , 'expected #{this} to have text #{exp}'
129
+ actual === text
130
+ , 'expected #{this} to have text #{exp}, but the text was #{act}'
128
131
  , 'expected #{this} not to have text #{exp}'
129
132
  , text
133
+ , actual
130
134
  );
131
135
  });
132
136
 
133
137
  chai.Assertion.addMethod('value', function (value) {
138
+ var actual = flag(this, 'object').val();
134
139
  this.assert(
135
140
  flag(this, 'object').val() === value
136
- , 'expected #{this} to have value #{exp}'
141
+ , 'expected #{this} to have value #{exp}, but the value was #{act}'
137
142
  , 'expected #{this} not to have value #{exp}'
138
143
  , value
144
+ , actual
139
145
  );
140
146
  });
141
147
 
@@ -178,21 +184,22 @@
178
184
 
179
185
  chai.Assertion.overwriteProperty('be', function (_super) {
180
186
  return function () {
181
- var be = function (selector) {
182
- var obj = flag(this, 'object');
183
- if (obj instanceof $) {
187
+ var obj = flag(this, 'object');
188
+ if (obj instanceof $) {
189
+ var be = function (selector) {
184
190
  this.assert(
185
191
  obj.is(selector)
186
192
  , 'expected #{this} to be #{exp}'
187
193
  , 'expected #{this} not to be #{exp}'
188
194
  , selector
189
195
  );
190
- } else {
191
- _super.apply(this, arguments);
192
- }
193
- };
194
- setPrototypeOf(be, this);
195
- return be;
196
+ };
197
+ setPrototypeOf(be, this);
198
+ return be;
199
+ }
200
+ else {
201
+ _super.call(this);
202
+ }
196
203
  }
197
204
  });
198
205
 
@@ -0,0 +1,26 @@
1
+ (function (chaiJsFactories) {
2
+ // Module systems magic dance.
3
+ if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
4
+ // NodeJS
5
+ module.exports = chaiJsFactories;
6
+ } else if (typeof define === "function" && define.amd) {
7
+ // AMD
8
+ define(['js-factories'], function ($) {
9
+ return function (chai, utils) {
10
+ return chaiJsFactories(chai, utils, Factory);
11
+ };
12
+ });
13
+ } else {
14
+ // Other environment (usually <script> tag): plug in to global chai instance directly.
15
+ chai.use(function (chai, utils) {
16
+ return chaiJsFactories(chai, utils, Factory);
17
+ });
18
+ }
19
+ }(function (chai, utils, jsFactories) {
20
+
21
+ jsFactories = jsFactories || Factory;
22
+
23
+
24
+ chai.factory = jsFactories;
25
+
26
+ }));
@@ -0,0 +1,183 @@
1
+ (function () {
2
+ 'use strict';
3
+ /*jshint -W003*/
4
+
5
+ if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
6
+ // NodeJS
7
+ module.exports = getPayload(
8
+ require('tv4'),
9
+ require('jsonpointer.js')
10
+ );
11
+ } else if (typeof define === 'function' && define.amd) {
12
+ // AMD
13
+ define('chai-json-schema', [
14
+ 'tv4',
15
+ 'jsonpointer'
16
+ ], function (tv4, jsonpointer) {
17
+ return getPayload(tv4, jsonpointer);
18
+ });
19
+ } else {
20
+ // Other environment (usually <script> tag): plug in to global chai instance directly.
21
+ chai.use(getPayload(
22
+ window.tv4,
23
+ window.jsonpointer
24
+ ));
25
+ }
26
+
27
+ function getPayload(tv4Module, jsonpointer) {
28
+ // return the chai plugin (a function)
29
+ return function (chai, utils) {
30
+ var assert = chai.assert;
31
+ var flag = utils.flag;
32
+
33
+ //check if we have all dependencies
34
+ assert.ok(tv4Module, 'tv4 dependency');
35
+ assert.ok(jsonpointer, 'jsonpointer dependency');
36
+
37
+ //export and use our own instance
38
+ chai.tv4 = tv4Module.freshApi();
39
+ chai.tv4.cyclicCheck = false;
40
+ chai.tv4.banUnknown = false;
41
+
42
+ function forEachI(arr, func, scope) {
43
+ for (var i = arr.length, ii = arr.length; i < ii; i++) {
44
+ func.call(scope, arr[i], i, arr);
45
+ }
46
+ }
47
+
48
+ //make a compact debug string from any object
49
+ function valueStrim(value, cutoff) {
50
+ var strimLimit = typeof cutoff === 'undefined' ? 60 : cutoff;
51
+
52
+ var t = typeof value;
53
+ if (t === 'function') {
54
+ return '[function]';
55
+ }
56
+ if (t === 'object') {
57
+ value = JSON.stringify(value);
58
+ if (value.length > strimLimit) {
59
+ value = value.substr(0, strimLimit) + '...';
60
+ }
61
+ return value;
62
+ }
63
+ if (t === 'string') {
64
+ if (value.length > strimLimit) {
65
+ return JSON.stringify(value.substr(0, strimLimit)) + '...';
66
+ }
67
+ return JSON.stringify(value);
68
+ }
69
+ return '' + value;
70
+ }
71
+
72
+ function extractSchemaLabel(schema, max) {
73
+ max = typeof max === 'undefined' ? 40 : max;
74
+ var label = '';
75
+ if (schema.id) {
76
+ label = schema.id;
77
+ }
78
+ if (schema.title) {
79
+ label += (label ? ' (' + schema.title + ')' : schema.title);
80
+ }
81
+ if (!label && schema.description) {
82
+ label = valueStrim(schema.description, max);
83
+ }
84
+ if (!label) {
85
+ label = valueStrim(schema, max);
86
+ }
87
+ return label;
88
+ }
89
+
90
+ //print validation errors
91
+ var formatResult = function (error, data, schema, indent) {
92
+ var schemaValue;
93
+ var dataValue;
94
+ var schemaLabel;
95
+
96
+ //assemble error string
97
+ var ret = '';
98
+ ret += '\n' + indent + error.message;
99
+
100
+ schemaLabel = extractSchemaLabel(schema, 60);
101
+ if (schemaLabel) {
102
+ ret += '\n' + indent + ' schema: ' + schemaLabel;
103
+ }
104
+ if (error.schemaPath) {
105
+ schemaValue = jsonpointer.get(schema, error.schemaPath);
106
+ ret += '\n' + indent + ' rule: ' + error.schemaPath + ' -> ' + valueStrim(schemaValue);
107
+ }
108
+ if (error.dataPath) {
109
+ dataValue = jsonpointer.get(data, error.dataPath);
110
+ ret += '\n' + indent + ' field: ' + error.dataPath + ' -> ' + utils.type(dataValue) + ': ' + valueStrim(dataValue);
111
+ }
112
+
113
+ //go deeper
114
+ /*if (error.subErrors) {
115
+ forEachI(error.subErrors, function (error) {
116
+ ret += formatResult(error, data, schema, indent + indent);
117
+ });
118
+ }*/
119
+ return ret;
120
+ };
121
+
122
+ //add the method
123
+ chai.Assertion.addMethod('jsonSchema', function (schema, msg) {
124
+ if (msg) {
125
+ flag(this, 'message', msg);
126
+ }
127
+ var obj = this._obj;
128
+
129
+ //note: don't assert.ok(obj) -> zero or empty string is a valid and describable json-value
130
+ assert.ok(schema, 'schema');
131
+
132
+ //single result
133
+ var result = chai.tv4.validateResult(obj, schema, chai.tv4.cyclicCheck, chai.tv4.banUnknown);
134
+ //assertion fails on missing schemas
135
+ var pass = result.valid && (result.missing.length === 0);
136
+
137
+ //assemble readable message
138
+ var label = extractSchemaLabel(schema, 30);
139
+
140
+ //assemble error report
141
+ var details = '';
142
+ if (!pass) {
143
+ var indent = ' ';
144
+ details += ' -> \'' + valueStrim(obj, 30) + '\'';
145
+
146
+ if (result.error) {
147
+ details += formatResult(result.error, obj, schema, indent);
148
+ }
149
+ else if (result.errors) {
150
+ forEachI(result.errors, function (error) {
151
+ details += formatResult(error, obj, schema, indent);
152
+ });
153
+ }
154
+
155
+ if (result.missing.length === 1) {
156
+ details += '\n' + 'missing 1 schema: ' + result.missing[0];
157
+ }
158
+ else if (result.missing.length > 0) {
159
+ details += '\n' + 'missing ' + result.missing.length + ' schemas:';
160
+ forEachI(result.missing, function (missing) {
161
+ details += '\n' + missing;
162
+ });
163
+ }
164
+ }
165
+ //pass hardcoded strings and no actual value (mocha forces nasty string diffs)
166
+ this.assert(
167
+ pass
168
+ , 'expected value to match json-schema \'' + label + '\'' + details
169
+ , 'expected value not to match json-schema \'' + label + '\'' + details
170
+ , label
171
+ );
172
+ });
173
+
174
+ //export tdd style
175
+ assert.jsonSchema = function (val, exp, msg) {
176
+ new chai.Assertion(val, msg).to.be.jsonSchema(exp);
177
+ };
178
+ assert.notJsonSchema = function (val, exp, msg) {
179
+ new chai.Assertion(val, msg).to.not.be.jsonSchema(exp);
180
+ };
181
+ };
182
+ }
183
+ }());
@@ -1,4 +1,4 @@
1
- // Generated by CoffeeScript 1.6.3
1
+ // Generated by CoffeeScript 1.7.1
2
2
  (function() {
3
3
  var __slice = [].slice;
4
4
 
@@ -27,10 +27,10 @@
27
27
  factories: {},
28
28
  define: function(factoryName, builder) {
29
29
  if (factoryName.indexOf('-') > 0) {
30
- throw "Factory name '" + factoryName + "' can't use - in name. It clashes with the traits construct";
30
+ throw new Error("Factory name '" + factoryName + "' can't use - in name. It clashes with the traits construct");
31
31
  }
32
32
  if (this.factories[factoryName] != null) {
33
- throw "Factory " + factoryName + " is already defined";
33
+ throw new Error("Factory " + factoryName + " is already defined");
34
34
  }
35
35
  return this.factories[factoryName] = {
36
36
  sequences: {},
@@ -43,7 +43,7 @@
43
43
  traits = nameWithTraits.split('-');
44
44
  factoryName = traits.pop();
45
45
  if (this.factories[factoryName] == null) {
46
- throw "Factory " + factoryName + " does not exist";
46
+ throw new Error("Factory " + factoryName + " does not exist");
47
47
  }
48
48
  f = this.factories[factoryName];
49
49
  obj = {
@@ -108,7 +108,7 @@ var Memoizer = function() {
108
108
  memoizer.is = this.is;
109
109
  };
110
110
 
111
- if (module && module.exports) { // Node.js
111
+ if (typeof(module) != 'undefined' && module.exports) { // Node.js
112
112
  /**
113
113
  * Return a new Memoizer object.
114
114
  *
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Sinon.JS 1.7.3, 2014/02/10
2
+ * Sinon.JS 1.10.3, 2014/08/25
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,
@@ -44,7 +44,7 @@
44
44
  * Copyright (c) 2010-2013 Christian Johansen
45
45
  */
46
46
 
47
- var sinon = (function (buster) {
47
+ var sinon = (function (formatio) {
48
48
  var div = typeof document != "undefined" && document.createElement("div");
49
49
  var hasOwn = Object.prototype.hasOwnProperty;
50
50
 
@@ -75,6 +75,10 @@ var sinon = (function (buster) {
75
75
  return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
76
76
  }
77
77
 
78
+ function isReallyNaN(val) {
79
+ return typeof val === 'number' && isNaN(val);
80
+ }
81
+
78
82
  function mirrorProperties(target, source) {
79
83
  for (var prop in source) {
80
84
  if (!hasOwn.call(target, prop)) {
@@ -97,26 +101,34 @@ var sinon = (function (buster) {
97
101
  throw new TypeError("Method wrapper should be function");
98
102
  }
99
103
 
100
- var wrappedMethod = object[property];
104
+ var wrappedMethod = object[property],
105
+ error;
101
106
 
102
107
  if (!isFunction(wrappedMethod)) {
103
- throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
108
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
104
109
  property + " as function");
110
+ } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
111
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
112
+ } else if (wrappedMethod.calledBefore) {
113
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
114
+ error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
105
115
  }
106
116
 
107
- if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
108
- throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
109
- }
110
-
111
- if (wrappedMethod.calledBefore) {
112
- var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
113
- throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
117
+ if (error) {
118
+ if (wrappedMethod && wrappedMethod._stack) {
119
+ error.stack += '\n--------------\n' + wrappedMethod._stack;
120
+ }
121
+ throw error;
114
122
  }
115
123
 
116
- // IE 8 does not support hasOwnProperty on the window object.
117
- var owned = hasOwn.call(object, property);
124
+ // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
125
+ // when using hasOwn.call on objects from other frames.
126
+ var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
118
127
  object[property] = method;
119
128
  method.displayName = property;
129
+ // Set up a stack trace which can be used later to find what line of
130
+ // code the original method was created on.
131
+ method._stack = (new Error('Stack Trace for original')).stack;
120
132
 
121
133
  method.restore = function () {
122
134
  // For prototype properties try to reset by delete first.
@@ -164,8 +176,13 @@ var sinon = (function (buster) {
164
176
  if (sinon.match && sinon.match.isMatcher(a)) {
165
177
  return a.test(b);
166
178
  }
167
- if (typeof a != "object" || typeof b != "object") {
168
- return a === b;
179
+
180
+ if (typeof a != 'object' || typeof b != 'object') {
181
+ if (isReallyNaN(a) && isReallyNaN(b)) {
182
+ return true;
183
+ } else {
184
+ return a === b;
185
+ }
169
186
  }
170
187
 
171
188
  if (isElement(a) || isElement(b)) {
@@ -180,34 +197,33 @@ var sinon = (function (buster) {
180
197
  return false;
181
198
  }
182
199
 
200
+ if (a instanceof RegExp && b instanceof RegExp) {
201
+ return (a.source === b.source) && (a.global === b.global) &&
202
+ (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
203
+ }
204
+
183
205
  var aString = Object.prototype.toString.call(a);
184
206
  if (aString != Object.prototype.toString.call(b)) {
185
207
  return false;
186
208
  }
187
209
 
188
- if (aString == "[object Array]") {
189
- if (a.length !== b.length) {
190
- return false;
191
- }
192
-
193
- for (var i = 0, l = a.length; i < l; i += 1) {
194
- if (!deepEqual(a[i], b[i])) {
195
- return false;
196
- }
197
- }
198
-
199
- return true;
200
- }
201
-
202
210
  if (aString == "[object Date]") {
203
211
  return a.valueOf() === b.valueOf();
204
212
  }
205
213
 
206
214
  var prop, aLength = 0, bLength = 0;
207
215
 
216
+ if (aString == "[object Array]" && a.length !== b.length) {
217
+ return false;
218
+ }
219
+
208
220
  for (prop in a) {
209
221
  aLength += 1;
210
222
 
223
+ if (!(prop in b)) {
224
+ return false;
225
+ }
226
+
211
227
  if (!deepEqual(a[prop], b[prop])) {
212
228
  return false;
213
229
  }
@@ -311,7 +327,7 @@ var sinon = (function (buster) {
311
327
  log: function () {},
312
328
 
313
329
  logError: function (label, err) {
314
- var msg = label + " threw exception: "
330
+ var msg = label + " threw exception: ";
315
331
  sinon.log(msg + "[" + err.name + "] " + err.message);
316
332
  if (err.stack) { sinon.log(err.stack); }
317
333
 
@@ -353,29 +369,35 @@ var sinon = (function (buster) {
353
369
  }
354
370
  };
355
371
 
356
- var isNode = typeof module == "object" && typeof require == "function";
372
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
373
+ var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
374
+
375
+ function makePublicAPI(require, exports, module) {
376
+ module.exports = sinon;
377
+ sinon.spy = require("./sinon/spy");
378
+ sinon.spyCall = require("./sinon/call");
379
+ sinon.behavior = require("./sinon/behavior");
380
+ sinon.stub = require("./sinon/stub");
381
+ sinon.mock = require("./sinon/mock");
382
+ sinon.collection = require("./sinon/collection");
383
+ sinon.assert = require("./sinon/assert");
384
+ sinon.sandbox = require("./sinon/sandbox");
385
+ sinon.test = require("./sinon/test");
386
+ sinon.testCase = require("./sinon/test_case");
387
+ sinon.match = require("./sinon/match");
388
+ }
357
389
 
358
- if (isNode) {
390
+ if (isAMD) {
391
+ define(makePublicAPI);
392
+ } else if (isNode) {
359
393
  try {
360
- buster = { format: require("buster-format") };
394
+ formatio = require("formatio");
361
395
  } catch (e) {}
362
- module.exports = sinon;
363
- module.exports.spy = require("./sinon/spy");
364
- module.exports.spyCall = require("./sinon/call");
365
- module.exports.stub = require("./sinon/stub");
366
- module.exports.mock = require("./sinon/mock");
367
- module.exports.collection = require("./sinon/collection");
368
- module.exports.assert = require("./sinon/assert");
369
- module.exports.sandbox = require("./sinon/sandbox");
370
- module.exports.test = require("./sinon/test");
371
- module.exports.testCase = require("./sinon/test_case");
372
- module.exports.assert = require("./sinon/assert");
373
- module.exports.match = require("./sinon/match");
374
- }
375
-
376
- if (buster) {
377
- var formatter = sinon.create(buster.format);
378
- formatter.quoteStrings = false;
396
+ makePublicAPI(require, exports, module);
397
+ }
398
+
399
+ if (formatio) {
400
+ var formatter = formatio.configure({ quoteStrings: false });
379
401
  sinon.format = function () {
380
402
  return formatter.ascii.apply(formatter, arguments);
381
403
  };
@@ -392,7 +414,7 @@ var sinon = (function (buster) {
392
414
  }
393
415
 
394
416
  return sinon;
395
- }(typeof buster == "object" && buster));
417
+ }(typeof formatio == "object" && formatio));
396
418
 
397
419
  /* @depend ../sinon.js */
398
420
  /*jslint eqeqeq: false, onevar: false, plusplus: false*/
@@ -407,7 +429,7 @@ var sinon = (function (buster) {
407
429
  */
408
430
 
409
431
  (function (sinon) {
410
- var commonJSModule = typeof module == "object" && typeof require == "function";
432
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
411
433
 
412
434
  if (!sinon && commonJSModule) {
413
435
  sinon = require("../sinon");
@@ -460,8 +482,10 @@ var sinon = (function (buster) {
460
482
  }
461
483
 
462
484
  matcher.or = function (m2) {
463
- if (!isMatcher(m2)) {
485
+ if (!arguments.length) {
464
486
  throw new TypeError("Matcher expected");
487
+ } else if (!isMatcher(m2)) {
488
+ m2 = match(m2);
465
489
  }
466
490
  var m1 = this;
467
491
  var or = sinon.create(matcher);
@@ -473,8 +497,10 @@ var sinon = (function (buster) {
473
497
  };
474
498
 
475
499
  matcher.and = function (m2) {
476
- if (!isMatcher(m2)) {
500
+ if (!arguments.length) {
477
501
  throw new TypeError("Matcher expected");
502
+ } else if (!isMatcher(m2)) {
503
+ m2 = match(m2);
478
504
  }
479
505
  var m1 = this;
480
506
  var and = sinon.create(matcher);
@@ -626,10 +652,12 @@ var sinon = (function (buster) {
626
652
  match.regexp = match.typeOf("regexp");
627
653
  match.date = match.typeOf("date");
628
654
 
629
- if (commonJSModule) {
655
+ sinon.match = match;
656
+
657
+ if (typeof define === "function" && define.amd) {
658
+ define(["module"], function(module) { module.exports = match; });
659
+ } else if (commonJSModule) {
630
660
  module.exports = match;
631
- } else {
632
- sinon.match = match;
633
661
  }
634
662
  }(typeof sinon == "object" && sinon || null));
635
663
 
@@ -651,7 +679,7 @@ var sinon = (function (buster) {
651
679
  */
652
680
 
653
681
  (function (sinon) {
654
- var commonJSModule = typeof module == "object" && typeof require == "function";
682
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
655
683
  if (!sinon && commonJSModule) {
656
684
  sinon = require("../sinon");
657
685
  }
@@ -724,8 +752,8 @@ var sinon = (function (buster) {
724
752
  return this.exception === error || this.exception.name === error;
725
753
  },
726
754
 
727
- calledWithNew: function calledWithNew(thisValue) {
728
- return this.thisValue instanceof this.proxy;
755
+ calledWithNew: function calledWithNew() {
756
+ return this.proxy.prototype && this.thisValue instanceof this.proxy;
729
757
  },
730
758
 
731
759
  calledBefore: function (other) {
@@ -825,13 +853,15 @@ var sinon = (function (buster) {
825
853
  proxyCall.callId = id;
826
854
 
827
855
  return proxyCall;
828
- };
856
+ }
829
857
  createSpyCall.toString = callProto.toString; // used by mocks
830
858
 
831
- if (commonJSModule) {
859
+ sinon.spyCall = createSpyCall;
860
+
861
+ if (typeof define === "function" && define.amd) {
862
+ define(["module"], function(module) { module.exports = createSpyCall; });
863
+ } else if (commonJSModule) {
832
864
  module.exports = createSpyCall;
833
- } else {
834
- sinon.spyCall = createSpyCall;
835
865
  }
836
866
  }(typeof sinon == "object" && sinon || null));
837
867
 
@@ -852,7 +882,7 @@ var sinon = (function (buster) {
852
882
  */
853
883
 
854
884
  (function (sinon) {
855
- var commonJSModule = typeof module == "object" && typeof require == "function";
885
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
856
886
  var push = Array.prototype.push;
857
887
  var slice = Array.prototype.slice;
858
888
  var callId = 0;
@@ -883,8 +913,6 @@ var sinon = (function (buster) {
883
913
  return;
884
914
  }
885
915
 
886
- var alen = args.length;
887
-
888
916
  for (var i = 0, l = fakes.length; i < l; i++) {
889
917
  if (fakes[i].matches(args, strict)) {
890
918
  return fakes[i];
@@ -985,27 +1013,42 @@ var sinon = (function (buster) {
985
1013
  push.call(this.args, args);
986
1014
  push.call(this.callIds, callId++);
987
1015
 
1016
+ // Make call properties available from within the spied function:
1017
+ createCallProperties.call(this);
1018
+
988
1019
  try {
989
1020
  if (matching) {
990
1021
  returnValue = matching.invoke(func, thisValue, args);
991
1022
  } else {
992
1023
  returnValue = (this.func || func).apply(thisValue, args);
993
1024
  }
1025
+
1026
+ var thisCall = this.getCall(this.callCount - 1);
1027
+ if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
1028
+ returnValue = thisValue;
1029
+ }
994
1030
  } catch (e) {
995
- push.call(this.returnValues, undefined);
996
1031
  exception = e;
997
- throw e;
998
- } finally {
999
- push.call(this.exceptions, exception);
1000
1032
  }
1001
1033
 
1034
+ push.call(this.exceptions, exception);
1002
1035
  push.call(this.returnValues, returnValue);
1003
1036
 
1037
+ // Make return value and exception available in the calls:
1004
1038
  createCallProperties.call(this);
1005
1039
 
1040
+ if (exception !== undefined) {
1041
+ throw exception;
1042
+ }
1043
+
1006
1044
  return returnValue;
1007
1045
  },
1008
1046
 
1047
+ named: function named(name) {
1048
+ this.displayName = name;
1049
+ return this;
1050
+ },
1051
+
1009
1052
  getCall: function getCall(i) {
1010
1053
  if (i < 0 || i >= this.callCount) {
1011
1054
  return null;
@@ -1016,6 +1059,17 @@ var sinon = (function (buster) {
1016
1059
  this.callIds[i]);
1017
1060
  },
1018
1061
 
1062
+ getCalls: function () {
1063
+ var calls = [];
1064
+ var i;
1065
+
1066
+ for (i = 0; i < this.callCount; i++) {
1067
+ calls.push(this.getCall(i));
1068
+ }
1069
+
1070
+ return calls;
1071
+ },
1072
+
1019
1073
  calledBefore: function calledBefore(spyFn) {
1020
1074
  if (!this.called) {
1021
1075
  return false;
@@ -1052,6 +1106,7 @@ var sinon = (function (buster) {
1052
1106
  var original = this;
1053
1107
  var fake = this._create();
1054
1108
  fake.matchingAguments = args;
1109
+ fake.parent = this;
1055
1110
  push.call(this.fakes, fake);
1056
1111
 
1057
1112
  fake.withArgs = function () {
@@ -1092,7 +1147,7 @@ var sinon = (function (buster) {
1092
1147
 
1093
1148
  if (typeof formatter == "function") {
1094
1149
  return formatter.call(null, spy, args);
1095
- } else if (!isNaN(parseInt(specifyer), 10)) {
1150
+ } else if (!isNaN(parseInt(specifyer, 10))) {
1096
1151
  return sinon.format(args[specifyer - 1]);
1097
1152
  }
1098
1153
 
@@ -1219,31 +1274,32 @@ var sinon = (function (buster) {
1219
1274
  sinon.extend(spy, spyApi);
1220
1275
 
1221
1276
  spy.spyCall = sinon.spyCall;
1277
+ sinon.spy = spy;
1222
1278
 
1223
- if (commonJSModule) {
1279
+ if (typeof define === "function" && define.amd) {
1280
+ define(["module"], function(module) { module.exports = spy; });
1281
+ } else if (commonJSModule) {
1224
1282
  module.exports = spy;
1225
- } else {
1226
- sinon.spy = spy;
1227
1283
  }
1228
1284
  }(typeof sinon == "object" && sinon || null));
1229
1285
 
1230
1286
  /**
1231
1287
  * @depend ../sinon.js
1232
- * @depend spy.js
1233
1288
  */
1234
1289
  /*jslint eqeqeq: false, onevar: false*/
1235
- /*global module, require, sinon*/
1290
+ /*global module, require, sinon, process, setImmediate, setTimeout*/
1236
1291
  /**
1237
- * Stub functions
1292
+ * Stub behavior
1238
1293
  *
1239
1294
  * @author Christian Johansen (christian@cjohansen.no)
1295
+ * @author Tim Fischbach (mail@timfischbach.de)
1240
1296
  * @license BSD
1241
1297
  *
1242
1298
  * Copyright (c) 2010-2013 Christian Johansen
1243
1299
  */
1244
1300
 
1245
1301
  (function (sinon) {
1246
- var commonJSModule = typeof module == "object" && typeof require == "function";
1302
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
1247
1303
 
1248
1304
  if (!sinon && commonJSModule) {
1249
1305
  sinon = require("../sinon");
@@ -1253,50 +1309,40 @@ var sinon = (function (buster) {
1253
1309
  return;
1254
1310
  }
1255
1311
 
1256
- function stub(object, property, func) {
1257
- if (!!func && typeof func != "function") {
1258
- throw new TypeError("Custom stub should be function");
1259
- }
1260
-
1261
- var wrapper;
1312
+ var slice = Array.prototype.slice;
1313
+ var join = Array.prototype.join;
1314
+ var proto;
1262
1315
 
1263
- if (func) {
1264
- wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
1316
+ var nextTick = (function () {
1317
+ if (typeof process === "object" && typeof process.nextTick === "function") {
1318
+ return process.nextTick;
1319
+ } else if (typeof setImmediate === "function") {
1320
+ return setImmediate;
1265
1321
  } else {
1266
- wrapper = stub.create();
1267
- }
1268
-
1269
- if (!object && !property) {
1270
- return sinon.stub.create();
1322
+ return function (callback) {
1323
+ setTimeout(callback, 0);
1324
+ };
1271
1325
  }
1326
+ })();
1272
1327
 
1273
- if (!property && !!object && typeof object == "object") {
1274
- for (var prop in object) {
1275
- if (typeof object[prop] === "function") {
1276
- stub(object, prop);
1277
- }
1278
- }
1279
-
1280
- return object;
1328
+ function throwsException(error, message) {
1329
+ if (typeof error == "string") {
1330
+ this.exception = new Error(message || "");
1331
+ this.exception.name = error;
1332
+ } else if (!error) {
1333
+ this.exception = new Error("Error");
1334
+ } else {
1335
+ this.exception = error;
1281
1336
  }
1282
1337
 
1283
- return sinon.wrapMethod(object, property, wrapper);
1338
+ return this;
1284
1339
  }
1285
1340
 
1286
- function getChangingValue(stub, property) {
1287
- var index = stub.callCount - 1;
1288
- var values = stub[property];
1289
- var prop = index in values ? values[index] : values[values.length - 1];
1290
- stub[property + "Last"] = prop;
1291
-
1292
- return prop;
1293
- }
1294
-
1295
- function getCallback(stub, args) {
1296
- var callArgAt = getChangingValue(stub, "callArgAts");
1341
+ function getCallback(behavior, args) {
1342
+ var callArgAt = behavior.callArgAt;
1297
1343
 
1298
1344
  if (callArgAt < 0) {
1299
- var callArgProp = getChangingValue(stub, "callArgProps");
1345
+ var callArgProp = behavior.callArgProp;
1300
1346
 
1301
1347
  for (var i = 0, l = args.length; i < l; ++i) {
1302
1348
  if (!callArgProp && typeof args[i] == "function") {
@@ -1315,19 +1361,17 @@ var sinon = (function (buster) {
1315
1361
  return args[callArgAt];
1316
1362
  }
1317
1363
 
1318
- var join = Array.prototype.join;
1319
-
1320
- function getCallbackError(stub, func, args) {
1321
- if (stub.callArgAtsLast < 0) {
1364
+ function getCallbackError(behavior, func, args) {
1365
+ if (behavior.callArgAt < 0) {
1322
1366
  var msg;
1323
1367
 
1324
- if (stub.callArgPropsLast) {
1325
- msg = sinon.functionName(stub) +
1326
- " expected to yield to '" + stub.callArgPropsLast +
1327
- "', but no object with such a property was passed."
1368
+ if (behavior.callArgProp) {
1369
+ msg = sinon.functionName(behavior.stub) +
1370
+ " expected to yield to '" + behavior.callArgProp +
1371
+ "', but no object with such a property was passed.";
1328
1372
  } else {
1329
- msg = sinon.functionName(stub) +
1330
- " expected to yield, but no callback was passed."
1373
+ msg = sinon.functionName(behavior.stub) +
1374
+ " expected to yield, but no callback was passed.";
1331
1375
  }
1332
1376
 
1333
1377
  if (args.length > 0) {
@@ -1337,264 +1381,400 @@ var sinon = (function (buster) {
1337
1381
  return msg;
1338
1382
  }
1339
1383
 
1340
- return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
1384
+ return "argument at index " + behavior.callArgAt + " is not a function: " + func;
1341
1385
  }
1342
1386
 
1343
- var nextTick = (function () {
1344
- if (typeof process === "object" && typeof process.nextTick === "function") {
1345
- return process.nextTick;
1346
- } else if (typeof setImmediate === "function") {
1347
- return setImmediate;
1348
- } else {
1349
- return function (callback) {
1350
- setTimeout(callback, 0);
1351
- };
1352
- }
1353
- })();
1354
-
1355
- function callCallback(stub, args) {
1356
- if (stub.callArgAts.length > 0) {
1357
- var func = getCallback(stub, args);
1387
+ function callCallback(behavior, args) {
1388
+ if (typeof behavior.callArgAt == "number") {
1389
+ var func = getCallback(behavior, args);
1358
1390
 
1359
1391
  if (typeof func != "function") {
1360
- throw new TypeError(getCallbackError(stub, func, args));
1392
+ throw new TypeError(getCallbackError(behavior, func, args));
1361
1393
  }
1362
1394
 
1363
- var callbackArguments = getChangingValue(stub, "callbackArguments");
1364
- var callbackContext = getChangingValue(stub, "callbackContexts");
1365
-
1366
- if (stub.callbackAsync) {
1395
+ if (behavior.callbackAsync) {
1367
1396
  nextTick(function() {
1368
- func.apply(callbackContext, callbackArguments);
1397
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
1369
1398
  });
1370
1399
  } else {
1371
- func.apply(callbackContext, callbackArguments);
1400
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
1372
1401
  }
1373
1402
  }
1374
1403
  }
1375
1404
 
1376
- var uuid = 0;
1405
+ proto = {
1406
+ create: function(stub) {
1407
+ var behavior = sinon.extend({}, sinon.behavior);
1408
+ delete behavior.create;
1409
+ behavior.stub = stub;
1377
1410
 
1378
- sinon.extend(stub, (function () {
1379
- var slice = Array.prototype.slice, proto;
1380
-
1381
- function throwsException(error, message) {
1382
- if (typeof error == "string") {
1383
- this.exception = new Error(message || "");
1384
- this.exception.name = error;
1385
- } else if (!error) {
1386
- this.exception = new Error("Error");
1387
- } else {
1388
- this.exception = error;
1411
+ return behavior;
1412
+ },
1413
+
1414
+ isPresent: function() {
1415
+ return (typeof this.callArgAt == 'number' ||
1416
+ this.exception ||
1417
+ typeof this.returnArgAt == 'number' ||
1418
+ this.returnThis ||
1419
+ this.returnValueDefined);
1420
+ },
1421
+
1422
+ invoke: function(context, args) {
1423
+ callCallback(this, args);
1424
+
1425
+ if (this.exception) {
1426
+ throw this.exception;
1427
+ } else if (typeof this.returnArgAt == 'number') {
1428
+ return args[this.returnArgAt];
1429
+ } else if (this.returnThis) {
1430
+ return context;
1431
+ }
1432
+
1433
+ return this.returnValue;
1434
+ },
1435
+
1436
+ onCall: function(index) {
1437
+ return this.stub.onCall(index);
1438
+ },
1439
+
1440
+ onFirstCall: function() {
1441
+ return this.stub.onFirstCall();
1442
+ },
1443
+
1444
+ onSecondCall: function() {
1445
+ return this.stub.onSecondCall();
1446
+ },
1447
+
1448
+ onThirdCall: function() {
1449
+ return this.stub.onThirdCall();
1450
+ },
1451
+
1452
+ withArgs: function(/* arguments */) {
1453
+ throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
1454
+ 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
1455
+ },
1456
+
1457
+ callsArg: function callsArg(pos) {
1458
+ if (typeof pos != "number") {
1459
+ throw new TypeError("argument index is not number");
1389
1460
  }
1390
1461
 
1462
+ this.callArgAt = pos;
1463
+ this.callbackArguments = [];
1464
+ this.callbackContext = undefined;
1465
+ this.callArgProp = undefined;
1466
+ this.callbackAsync = false;
1467
+
1391
1468
  return this;
1392
- }
1469
+ },
1393
1470
 
1394
- proto = {
1395
- create: function create() {
1396
- var functionStub = function () {
1471
+ callsArgOn: function callsArgOn(pos, context) {
1472
+ if (typeof pos != "number") {
1473
+ throw new TypeError("argument index is not number");
1474
+ }
1475
+ if (typeof context != "object") {
1476
+ throw new TypeError("argument context is not an object");
1477
+ }
1397
1478
 
1398
- callCallback(functionStub, arguments);
1479
+ this.callArgAt = pos;
1480
+ this.callbackArguments = [];
1481
+ this.callbackContext = context;
1482
+ this.callArgProp = undefined;
1483
+ this.callbackAsync = false;
1399
1484
 
1400
- if (functionStub.exception) {
1401
- throw functionStub.exception;
1402
- } else if (typeof functionStub.returnArgAt == 'number') {
1403
- return arguments[functionStub.returnArgAt];
1404
- } else if (functionStub.returnThis) {
1405
- return this;
1406
- }
1407
- return functionStub.returnValue;
1408
- };
1485
+ return this;
1486
+ },
1409
1487
 
1410
- functionStub.id = "stub#" + uuid++;
1411
- var orig = functionStub;
1412
- functionStub = sinon.spy.create(functionStub);
1413
- functionStub.func = orig;
1488
+ callsArgWith: function callsArgWith(pos) {
1489
+ if (typeof pos != "number") {
1490
+ throw new TypeError("argument index is not number");
1491
+ }
1414
1492
 
1415
- functionStub.callArgAts = [];
1416
- functionStub.callbackArguments = [];
1417
- functionStub.callbackContexts = [];
1418
- functionStub.callArgProps = [];
1493
+ this.callArgAt = pos;
1494
+ this.callbackArguments = slice.call(arguments, 1);
1495
+ this.callbackContext = undefined;
1496
+ this.callArgProp = undefined;
1497
+ this.callbackAsync = false;
1419
1498
 
1420
- sinon.extend(functionStub, stub);
1421
- functionStub._create = sinon.stub.create;
1422
- functionStub.displayName = "stub";
1423
- functionStub.toString = sinon.functionToString;
1499
+ return this;
1500
+ },
1424
1501
 
1425
- return functionStub;
1426
- },
1502
+ callsArgOnWith: function callsArgWith(pos, context) {
1503
+ if (typeof pos != "number") {
1504
+ throw new TypeError("argument index is not number");
1505
+ }
1506
+ if (typeof context != "object") {
1507
+ throw new TypeError("argument context is not an object");
1508
+ }
1427
1509
 
1428
- resetBehavior: function () {
1429
- var i;
1510
+ this.callArgAt = pos;
1511
+ this.callbackArguments = slice.call(arguments, 2);
1512
+ this.callbackContext = context;
1513
+ this.callArgProp = undefined;
1514
+ this.callbackAsync = false;
1430
1515
 
1431
- this.callArgAts = [];
1432
- this.callbackArguments = [];
1433
- this.callbackContexts = [];
1434
- this.callArgProps = [];
1516
+ return this;
1517
+ },
1435
1518
 
1436
- delete this.returnValue;
1437
- delete this.returnArgAt;
1438
- this.returnThis = false;
1519
+ yields: function () {
1520
+ this.callArgAt = -1;
1521
+ this.callbackArguments = slice.call(arguments, 0);
1522
+ this.callbackContext = undefined;
1523
+ this.callArgProp = undefined;
1524
+ this.callbackAsync = false;
1439
1525
 
1440
- if (this.fakes) {
1441
- for (i = 0; i < this.fakes.length; i++) {
1442
- this.fakes[i].resetBehavior();
1443
- }
1444
- }
1445
- },
1526
+ return this;
1527
+ },
1446
1528
 
1447
- returns: function returns(value) {
1448
- this.returnValue = value;
1529
+ yieldsOn: function (context) {
1530
+ if (typeof context != "object") {
1531
+ throw new TypeError("argument context is not an object");
1532
+ }
1449
1533
 
1450
- return this;
1451
- },
1534
+ this.callArgAt = -1;
1535
+ this.callbackArguments = slice.call(arguments, 1);
1536
+ this.callbackContext = context;
1537
+ this.callArgProp = undefined;
1538
+ this.callbackAsync = false;
1452
1539
 
1453
- returnsArg: function returnsArg(pos) {
1454
- if (typeof pos != "number") {
1455
- throw new TypeError("argument index is not number");
1456
- }
1540
+ return this;
1541
+ },
1457
1542
 
1458
- this.returnArgAt = pos;
1543
+ yieldsTo: function (prop) {
1544
+ this.callArgAt = -1;
1545
+ this.callbackArguments = slice.call(arguments, 1);
1546
+ this.callbackContext = undefined;
1547
+ this.callArgProp = prop;
1548
+ this.callbackAsync = false;
1459
1549
 
1460
- return this;
1461
- },
1550
+ return this;
1551
+ },
1462
1552
 
1463
- returnsThis: function returnsThis() {
1464
- this.returnThis = true;
1553
+ yieldsToOn: function (prop, context) {
1554
+ if (typeof context != "object") {
1555
+ throw new TypeError("argument context is not an object");
1556
+ }
1465
1557
 
1466
- return this;
1467
- },
1558
+ this.callArgAt = -1;
1559
+ this.callbackArguments = slice.call(arguments, 2);
1560
+ this.callbackContext = context;
1561
+ this.callArgProp = prop;
1562
+ this.callbackAsync = false;
1468
1563
 
1469
- "throws": throwsException,
1470
- throwsException: throwsException,
1564
+ return this;
1565
+ },
1471
1566
 
1472
- callsArg: function callsArg(pos) {
1473
- if (typeof pos != "number") {
1474
- throw new TypeError("argument index is not number");
1475
- }
1476
1567
 
1477
- this.callArgAts.push(pos);
1478
- this.callbackArguments.push([]);
1479
- this.callbackContexts.push(undefined);
1480
- this.callArgProps.push(undefined);
1568
+ "throws": throwsException,
1569
+ throwsException: throwsException,
1481
1570
 
1482
- return this;
1483
- },
1571
+ returns: function returns(value) {
1572
+ this.returnValue = value;
1573
+ this.returnValueDefined = true;
1484
1574
 
1485
- callsArgOn: function callsArgOn(pos, context) {
1486
- if (typeof pos != "number") {
1487
- throw new TypeError("argument index is not number");
1488
- }
1489
- if (typeof context != "object") {
1490
- throw new TypeError("argument context is not an object");
1491
- }
1575
+ return this;
1576
+ },
1492
1577
 
1493
- this.callArgAts.push(pos);
1494
- this.callbackArguments.push([]);
1495
- this.callbackContexts.push(context);
1496
- this.callArgProps.push(undefined);
1578
+ returnsArg: function returnsArg(pos) {
1579
+ if (typeof pos != "number") {
1580
+ throw new TypeError("argument index is not number");
1581
+ }
1497
1582
 
1498
- return this;
1499
- },
1583
+ this.returnArgAt = pos;
1500
1584
 
1501
- callsArgWith: function callsArgWith(pos) {
1502
- if (typeof pos != "number") {
1503
- throw new TypeError("argument index is not number");
1504
- }
1585
+ return this;
1586
+ },
1505
1587
 
1506
- this.callArgAts.push(pos);
1507
- this.callbackArguments.push(slice.call(arguments, 1));
1508
- this.callbackContexts.push(undefined);
1509
- this.callArgProps.push(undefined);
1588
+ returnsThis: function returnsThis() {
1589
+ this.returnThis = true;
1510
1590
 
1511
- return this;
1512
- },
1591
+ return this;
1592
+ }
1593
+ };
1513
1594
 
1514
- callsArgOnWith: function callsArgWith(pos, context) {
1515
- if (typeof pos != "number") {
1516
- throw new TypeError("argument index is not number");
1517
- }
1518
- if (typeof context != "object") {
1519
- throw new TypeError("argument context is not an object");
1520
- }
1595
+ // create asynchronous versions of callsArg* and yields* methods
1596
+ for (var method in proto) {
1597
+ // need to avoid creating anotherasync versions of the newly added async methods
1598
+ if (proto.hasOwnProperty(method) &&
1599
+ method.match(/^(callsArg|yields)/) &&
1600
+ !method.match(/Async/)) {
1601
+ proto[method + 'Async'] = (function (syncFnName) {
1602
+ return function () {
1603
+ var result = this[syncFnName].apply(this, arguments);
1604
+ this.callbackAsync = true;
1605
+ return result;
1606
+ };
1607
+ })(method);
1608
+ }
1609
+ }
1521
1610
 
1522
- this.callArgAts.push(pos);
1523
- this.callbackArguments.push(slice.call(arguments, 2));
1524
- this.callbackContexts.push(context);
1525
- this.callArgProps.push(undefined);
1611
+ sinon.behavior = proto;
1526
1612
 
1527
- return this;
1528
- },
1613
+ if (typeof define === "function" && define.amd) {
1614
+ define(["module"], function(module) { module.exports = proto; });
1615
+ } else if (commonJSModule) {
1616
+ module.exports = proto;
1617
+ }
1618
+ }(typeof sinon == "object" && sinon || null));
1529
1619
 
1530
- yields: function () {
1531
- this.callArgAts.push(-1);
1532
- this.callbackArguments.push(slice.call(arguments, 0));
1533
- this.callbackContexts.push(undefined);
1534
- this.callArgProps.push(undefined);
1620
+ /**
1621
+ * @depend ../sinon.js
1622
+ * @depend spy.js
1623
+ * @depend behavior.js
1624
+ */
1625
+ /*jslint eqeqeq: false, onevar: false*/
1626
+ /*global module, require, sinon*/
1627
+ /**
1628
+ * Stub functions
1629
+ *
1630
+ * @author Christian Johansen (christian@cjohansen.no)
1631
+ * @license BSD
1632
+ *
1633
+ * Copyright (c) 2010-2013 Christian Johansen
1634
+ */
1535
1635
 
1536
- return this;
1537
- },
1636
+ (function (sinon) {
1637
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
1538
1638
 
1539
- yieldsOn: function (context) {
1540
- if (typeof context != "object") {
1541
- throw new TypeError("argument context is not an object");
1639
+ if (!sinon && commonJSModule) {
1640
+ sinon = require("../sinon");
1641
+ }
1642
+
1643
+ if (!sinon) {
1644
+ return;
1645
+ }
1646
+
1647
+ function stub(object, property, func) {
1648
+ if (!!func && typeof func != "function") {
1649
+ throw new TypeError("Custom stub should be function");
1650
+ }
1651
+
1652
+ var wrapper;
1653
+
1654
+ if (func) {
1655
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
1656
+ } else {
1657
+ wrapper = stub.create();
1658
+ }
1659
+
1660
+ if (!object && typeof property === "undefined") {
1661
+ return sinon.stub.create();
1662
+ }
1663
+
1664
+ if (typeof property === "undefined" && typeof object == "object") {
1665
+ for (var prop in object) {
1666
+ if (typeof object[prop] === "function") {
1667
+ stub(object, prop);
1542
1668
  }
1669
+ }
1543
1670
 
1544
- this.callArgAts.push(-1);
1545
- this.callbackArguments.push(slice.call(arguments, 1));
1546
- this.callbackContexts.push(context);
1547
- this.callArgProps.push(undefined);
1671
+ return object;
1672
+ }
1548
1673
 
1549
- return this;
1674
+ return sinon.wrapMethod(object, property, wrapper);
1675
+ }
1676
+
1677
+ function getDefaultBehavior(stub) {
1678
+ return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
1679
+ }
1680
+
1681
+ function getParentBehaviour(stub) {
1682
+ return (stub.parent && getCurrentBehavior(stub.parent));
1683
+ }
1684
+
1685
+ function getCurrentBehavior(stub) {
1686
+ var behavior = stub.behaviors[stub.callCount - 1];
1687
+ return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
1688
+ }
1689
+
1690
+ var uuid = 0;
1691
+
1692
+ sinon.extend(stub, (function () {
1693
+ var proto = {
1694
+ create: function create() {
1695
+ var functionStub = function () {
1696
+ return getCurrentBehavior(functionStub).invoke(this, arguments);
1697
+ };
1698
+
1699
+ functionStub.id = "stub#" + uuid++;
1700
+ var orig = functionStub;
1701
+ functionStub = sinon.spy.create(functionStub);
1702
+ functionStub.func = orig;
1703
+
1704
+ sinon.extend(functionStub, stub);
1705
+ functionStub._create = sinon.stub.create;
1706
+ functionStub.displayName = "stub";
1707
+ functionStub.toString = sinon.functionToString;
1708
+
1709
+ functionStub.defaultBehavior = null;
1710
+ functionStub.behaviors = [];
1711
+
1712
+ return functionStub;
1550
1713
  },
1551
1714
 
1552
- yieldsTo: function (prop) {
1553
- this.callArgAts.push(-1);
1554
- this.callbackArguments.push(slice.call(arguments, 1));
1555
- this.callbackContexts.push(undefined);
1556
- this.callArgProps.push(prop);
1715
+ resetBehavior: function () {
1716
+ var i;
1717
+
1718
+ this.defaultBehavior = null;
1719
+ this.behaviors = [];
1557
1720
 
1558
- return this;
1721
+ delete this.returnValue;
1722
+ delete this.returnArgAt;
1723
+ this.returnThis = false;
1724
+
1725
+ if (this.fakes) {
1726
+ for (i = 0; i < this.fakes.length; i++) {
1727
+ this.fakes[i].resetBehavior();
1728
+ }
1729
+ }
1559
1730
  },
1560
1731
 
1561
- yieldsToOn: function (prop, context) {
1562
- if (typeof context != "object") {
1563
- throw new TypeError("argument context is not an object");
1732
+ onCall: function(index) {
1733
+ if (!this.behaviors[index]) {
1734
+ this.behaviors[index] = sinon.behavior.create(this);
1564
1735
  }
1565
1736
 
1566
- this.callArgAts.push(-1);
1567
- this.callbackArguments.push(slice.call(arguments, 2));
1568
- this.callbackContexts.push(context);
1569
- this.callArgProps.push(prop);
1737
+ return this.behaviors[index];
1738
+ },
1570
1739
 
1571
- return this;
1740
+ onFirstCall: function() {
1741
+ return this.onCall(0);
1742
+ },
1743
+
1744
+ onSecondCall: function() {
1745
+ return this.onCall(1);
1746
+ },
1747
+
1748
+ onThirdCall: function() {
1749
+ return this.onCall(2);
1572
1750
  }
1573
1751
  };
1574
1752
 
1575
- // create asynchronous versions of callsArg* and yields* methods
1576
- for (var method in proto) {
1577
- // need to avoid creating anotherasync versions of the newly added async methods
1578
- if (proto.hasOwnProperty(method) &&
1579
- method.match(/^(callsArg|yields|thenYields$)/) &&
1580
- !method.match(/Async/)) {
1581
- proto[method + 'Async'] = (function (syncFnName) {
1582
- return function () {
1583
- this.callbackAsync = true;
1584
- return this[syncFnName].apply(this, arguments);
1753
+ for (var method in sinon.behavior) {
1754
+ if (sinon.behavior.hasOwnProperty(method) &&
1755
+ !proto.hasOwnProperty(method) &&
1756
+ method != 'create' &&
1757
+ method != 'withArgs' &&
1758
+ method != 'invoke') {
1759
+ proto[method] = (function(behaviorMethod) {
1760
+ return function() {
1761
+ this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
1762
+ this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
1763
+ return this;
1585
1764
  };
1586
- })(method);
1765
+ }(method));
1587
1766
  }
1588
1767
  }
1589
1768
 
1590
1769
  return proto;
1591
-
1592
1770
  }()));
1593
1771
 
1594
- if (commonJSModule) {
1772
+ sinon.stub = stub;
1773
+
1774
+ if (typeof define === "function" && define.amd) {
1775
+ define(["module"], function(module) { module.exports = stub; });
1776
+ } else if (commonJSModule) {
1595
1777
  module.exports = stub;
1596
- } else {
1597
- sinon.stub = stub;
1598
1778
  }
1599
1779
  }(typeof sinon == "object" && sinon || null));
1600
1780
 
@@ -1614,8 +1794,9 @@ var sinon = (function (buster) {
1614
1794
  */
1615
1795
 
1616
1796
  (function (sinon) {
1617
- var commonJSModule = typeof module == "object" && typeof require == "function";
1797
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
1618
1798
  var push = [].push;
1799
+ var match;
1619
1800
 
1620
1801
  if (!sinon && commonJSModule) {
1621
1802
  sinon = require("../sinon");
@@ -1625,6 +1806,12 @@ var sinon = (function (buster) {
1625
1806
  return;
1626
1807
  }
1627
1808
 
1809
+ match = sinon.match;
1810
+
1811
+ if (!match && commonJSModule) {
1812
+ match = require("./match");
1813
+ }
1814
+
1628
1815
  function mock(object) {
1629
1816
  if (!object) {
1630
1817
  return sinon.expectation.create("Anonymous mock");
@@ -1801,8 +1988,16 @@ var sinon = (function (buster) {
1801
1988
  if (typeof expectation.maxCalls != "number") {
1802
1989
  return false;
1803
1990
  }
1804
-
1805
- return expectation.callCount == expectation.maxCalls;
1991
+
1992
+ return expectation.callCount == expectation.maxCalls;
1993
+ }
1994
+
1995
+ function verifyMatcher(possibleMatcher, arg){
1996
+ if (match && match.isMatcher(possibleMatcher)) {
1997
+ return possibleMatcher.test(arg);
1998
+ } else {
1999
+ return true;
2000
+ }
1806
2001
  }
1807
2002
 
1808
2003
  return {
@@ -1914,6 +2109,12 @@ var sinon = (function (buster) {
1914
2109
  }
1915
2110
 
1916
2111
  for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2112
+
2113
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2114
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
2115
+ ", didn't match " + this.expectedArguments.toString());
2116
+ }
2117
+
1917
2118
  if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
1918
2119
  sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
1919
2120
  ", expected " + sinon.format(this.expectedArguments));
@@ -1946,6 +2147,10 @@ var sinon = (function (buster) {
1946
2147
  }
1947
2148
 
1948
2149
  for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
2150
+ if (!verifyMatcher(this.expectedArguments[i],args[i])) {
2151
+ return false;
2152
+ }
2153
+
1949
2154
  if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
1950
2155
  return false;
1951
2156
  }
@@ -2015,10 +2220,12 @@ var sinon = (function (buster) {
2015
2220
  };
2016
2221
  }());
2017
2222
 
2018
- if (commonJSModule) {
2223
+ sinon.mock = mock;
2224
+
2225
+ if (typeof define === "function" && define.amd) {
2226
+ define(["module"], function(module) { module.exports = mock; });
2227
+ } else if (commonJSModule) {
2019
2228
  module.exports = mock;
2020
- } else {
2021
- sinon.mock = mock;
2022
2229
  }
2023
2230
  }(typeof sinon == "object" && sinon || null));
2024
2231
 
@@ -2039,7 +2246,7 @@ var sinon = (function (buster) {
2039
2246
  */
2040
2247
 
2041
2248
  (function (sinon) {
2042
- var commonJSModule = typeof module == "object" && typeof require == "function";
2249
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
2043
2250
  var push = [].push;
2044
2251
  var hasOwnProperty = Object.prototype.hasOwnProperty;
2045
2252
 
@@ -2168,10 +2375,12 @@ var sinon = (function (buster) {
2168
2375
  }
2169
2376
  };
2170
2377
 
2171
- if (commonJSModule) {
2378
+ sinon.collection = collection;
2379
+
2380
+ if (typeof define === "function" && define.amd) {
2381
+ define(["module"], function(module) { module.exports = collection; });
2382
+ } else if (commonJSModule) {
2172
2383
  module.exports = collection;
2173
- } else {
2174
- sinon.collection = collection;
2175
2384
  }
2176
2385
  }(typeof sinon == "object" && sinon || null));
2177
2386
 
@@ -2200,6 +2409,13 @@ if (typeof sinon == "undefined") {
2200
2409
  }
2201
2410
 
2202
2411
  (function (global) {
2412
+ // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
2413
+ // browsers, a number.
2414
+ // see https://github.com/cjohansen/Sinon.JS/pull/436
2415
+ var timeoutResult = setTimeout(function() {}, 0);
2416
+ var addTimerReturnsObject = typeof timeoutResult === 'object';
2417
+ clearTimeout(timeoutResult);
2418
+
2203
2419
  var id = 1;
2204
2420
 
2205
2421
  function addTimer(args, recurring) {
@@ -2207,6 +2423,10 @@ if (typeof sinon == "undefined") {
2207
2423
  throw new Error("Function requires at least 1 parameter");
2208
2424
  }
2209
2425
 
2426
+ if (typeof args[0] === "undefined") {
2427
+ throw new Error("Callback must be provided to timer calls");
2428
+ }
2429
+
2210
2430
  var toId = id++;
2211
2431
  var delay = args[1] || 0;
2212
2432
 
@@ -2225,7 +2445,16 @@ if (typeof sinon == "undefined") {
2225
2445
  this.timeouts[toId].interval = delay;
2226
2446
  }
2227
2447
 
2228
- return toId;
2448
+ if (addTimerReturnsObject) {
2449
+ return {
2450
+ id: toId,
2451
+ ref: function() {},
2452
+ unref: function() {}
2453
+ };
2454
+ }
2455
+ else {
2456
+ return toId;
2457
+ }
2229
2458
  }
2230
2459
 
2231
2460
  function parseTime(str) {
@@ -2291,10 +2520,18 @@ if (typeof sinon == "undefined") {
2291
2520
  },
2292
2521
 
2293
2522
  clearTimeout: function clearTimeout(timerId) {
2523
+ if (!timerId) {
2524
+ // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel
2525
+ return;
2526
+ }
2294
2527
  if (!this.timeouts) {
2295
2528
  this.timeouts = [];
2296
2529
  }
2297
-
2530
+ // in Node, timerId is an object with .ref()/.unref(), and
2531
+ // its .id field is the actual timer id.
2532
+ if (typeof timerId === 'object') {
2533
+ timerId = timerId.id
2534
+ }
2298
2535
  if (timerId in this.timeouts) {
2299
2536
  delete this.timeouts[timerId];
2300
2537
  }
@@ -2308,6 +2545,16 @@ if (typeof sinon == "undefined") {
2308
2545
  this.clearTimeout(timerId);
2309
2546
  },
2310
2547
 
2548
+ setImmediate: function setImmediate(callback) {
2549
+ var passThruArgs = Array.prototype.slice.call(arguments, 1);
2550
+
2551
+ return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
2552
+ },
2553
+
2554
+ clearImmediate: function clearImmediate(timerId) {
2555
+ this.clearTimeout(timerId);
2556
+ },
2557
+
2311
2558
  tick: function tick(ms) {
2312
2559
  ms = typeof ms == "number" ? ms : parseTime(ms);
2313
2560
  var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
@@ -2338,7 +2585,7 @@ if (typeof sinon == "undefined") {
2338
2585
  },
2339
2586
 
2340
2587
  firstTimerInRange: function (from, to) {
2341
- var timer, smallest, originalTimer;
2588
+ var timer, smallest = null, originalTimer;
2342
2589
 
2343
2590
  for (var id in this.timeouts) {
2344
2591
  if (this.timeouts.hasOwnProperty(id)) {
@@ -2346,7 +2593,7 @@ if (typeof sinon == "undefined") {
2346
2593
  continue;
2347
2594
  }
2348
2595
 
2349
- if (!smallest || this.timeouts[id].callAt < smallest) {
2596
+ if (smallest === null || this.timeouts[id].callAt < smallest) {
2350
2597
  originalTimer = this.timeouts[id];
2351
2598
  smallest = this.timeouts[id].callAt;
2352
2599
 
@@ -2452,21 +2699,39 @@ if (typeof sinon == "undefined") {
2452
2699
  target.parse = source.parse;
2453
2700
  target.UTC = source.UTC;
2454
2701
  target.prototype.toUTCString = source.prototype.toUTCString;
2702
+
2703
+ for (var prop in source) {
2704
+ if (source.hasOwnProperty(prop)) {
2705
+ target[prop] = source[prop];
2706
+ }
2707
+ }
2708
+
2455
2709
  return target;
2456
2710
  }
2457
2711
 
2458
2712
  var methods = ["Date", "setTimeout", "setInterval",
2459
2713
  "clearTimeout", "clearInterval"];
2460
2714
 
2715
+ if (typeof global.setImmediate !== "undefined") {
2716
+ methods.push("setImmediate");
2717
+ }
2718
+
2719
+ if (typeof global.clearImmediate !== "undefined") {
2720
+ methods.push("clearImmediate");
2721
+ }
2722
+
2461
2723
  function restore() {
2462
2724
  var method;
2463
2725
 
2464
2726
  for (var i = 0, l = this.methods.length; i < l; i++) {
2465
2727
  method = this.methods[i];
2728
+
2466
2729
  if (global[method].hadOwnProperty) {
2467
2730
  global[method] = this["_" + method];
2468
2731
  } else {
2469
- delete global[method];
2732
+ try {
2733
+ delete global[method];
2734
+ } catch (e) {}
2470
2735
  }
2471
2736
  }
2472
2737
 
@@ -2517,12 +2782,14 @@ if (typeof sinon == "undefined") {
2517
2782
  sinon.timers = {
2518
2783
  setTimeout: setTimeout,
2519
2784
  clearTimeout: clearTimeout,
2785
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
2786
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
2520
2787
  setInterval: setInterval,
2521
2788
  clearInterval: clearInterval,
2522
2789
  Date: Date
2523
2790
  };
2524
2791
 
2525
- if (typeof module == "object" && typeof require == "function") {
2792
+ if (typeof module !== 'undefined' && module.exports) {
2526
2793
  module.exports = sinon;
2527
2794
  }
2528
2795
 
@@ -2567,14 +2834,33 @@ if (typeof sinon == "undefined") {
2567
2834
  }
2568
2835
  };
2569
2836
 
2837
+ sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
2838
+ this.initEvent(type, false, false, target);
2839
+ this.loaded = progressEventRaw.loaded || null;
2840
+ this.total = progressEventRaw.total || null;
2841
+ };
2842
+
2843
+ sinon.ProgressEvent.prototype = new sinon.Event();
2844
+
2845
+ sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
2846
+
2847
+ sinon.CustomEvent = function CustomEvent(type, customData, target) {
2848
+ this.initEvent(type, false, false, target);
2849
+ this.detail = customData.detail || null;
2850
+ };
2851
+
2852
+ sinon.CustomEvent.prototype = new sinon.Event();
2853
+
2854
+ sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
2855
+
2570
2856
  sinon.EventTarget = {
2571
- addEventListener: function addEventListener(event, listener, useCapture) {
2857
+ addEventListener: function addEventListener(event, listener) {
2572
2858
  this.eventListeners = this.eventListeners || {};
2573
2859
  this.eventListeners[event] = this.eventListeners[event] || [];
2574
2860
  push.call(this.eventListeners[event], listener);
2575
2861
  },
2576
2862
 
2577
- removeEventListener: function removeEventListener(event, listener, useCapture) {
2863
+ removeEventListener: function removeEventListener(event, listener) {
2578
2864
  var listeners = this.eventListeners && this.eventListeners[event] || [];
2579
2865
 
2580
2866
  for (var i = 0, l = listeners.length; i < l; ++i) {
@@ -2616,13 +2902,15 @@ if (typeof sinon == "undefined") {
2616
2902
  * Copyright (c) 2010-2013 Christian Johansen
2617
2903
  */
2618
2904
 
2619
- if (typeof sinon == "undefined") {
2620
- this.sinon = {};
2621
- }
2622
- sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2623
-
2624
2905
  // wrapper for global
2625
2906
  (function(global) {
2907
+ if (typeof sinon === "undefined") {
2908
+ global.sinon = {};
2909
+ }
2910
+
2911
+ var supportsProgress = typeof ProgressEvent !== "undefined";
2912
+ var supportsCustomEvent = typeof CustomEvent !== "undefined";
2913
+ sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
2626
2914
  var xhr = sinon.xhr;
2627
2915
  xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
2628
2916
  xhr.GlobalActiveXObject = global.ActiveXObject;
@@ -2630,6 +2918,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2630
2918
  xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
2631
2919
  xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
2632
2920
  ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
2921
+ xhr.supportsCORS = xhr.supportsXHR && 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
2633
2922
 
2634
2923
  /*jsl:ignore*/
2635
2924
  var unsafeHeaders = {
@@ -2660,6 +2949,11 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2660
2949
  this.requestBody = null;
2661
2950
  this.status = 0;
2662
2951
  this.statusText = "";
2952
+ this.upload = new UploadProgress();
2953
+ if (sinon.xhr.supportsCORS) {
2954
+ this.withCredentials = false;
2955
+ }
2956
+
2663
2957
 
2664
2958
  var xhr = this;
2665
2959
  var events = ["loadstart", "load", "abort", "loadend"];
@@ -2669,7 +2963,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2669
2963
  var listener = xhr["on" + eventName];
2670
2964
 
2671
2965
  if (listener && typeof listener == "function") {
2672
- listener(event);
2966
+ listener.call(this, event);
2673
2967
  }
2674
2968
  });
2675
2969
  }
@@ -2683,6 +2977,41 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2683
2977
  }
2684
2978
  }
2685
2979
 
2980
+ // An upload object is created for each
2981
+ // FakeXMLHttpRequest and allows upload
2982
+ // events to be simulated using uploadProgress
2983
+ // and uploadError.
2984
+ function UploadProgress() {
2985
+ this.eventListeners = {
2986
+ "progress": [],
2987
+ "load": [],
2988
+ "abort": [],
2989
+ "error": []
2990
+ }
2991
+ }
2992
+
2993
+ UploadProgress.prototype.addEventListener = function(event, listener) {
2994
+ this.eventListeners[event].push(listener);
2995
+ };
2996
+
2997
+ UploadProgress.prototype.removeEventListener = function(event, listener) {
2998
+ var listeners = this.eventListeners[event] || [];
2999
+
3000
+ for (var i = 0, l = listeners.length; i < l; ++i) {
3001
+ if (listeners[i] == listener) {
3002
+ return listeners.splice(i, 1);
3003
+ }
3004
+ }
3005
+ };
3006
+
3007
+ UploadProgress.prototype.dispatchEvent = function(event) {
3008
+ var listeners = this.eventListeners[event.type] || [];
3009
+
3010
+ for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
3011
+ listener(event);
3012
+ }
3013
+ };
3014
+
2686
3015
  function verifyState(xhr) {
2687
3016
  if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
2688
3017
  throw new Error("INVALID_STATE_ERR");
@@ -2704,7 +3033,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2704
3033
  function some(collection, callback) {
2705
3034
  for (var index = 0; index < collection.length; index++) {
2706
3035
  if(callback(collection[index]) === true) return true;
2707
- };
3036
+ }
2708
3037
  return false;
2709
3038
  }
2710
3039
  // largest arity in XHR is 5 - XHR#open
@@ -2716,7 +3045,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2716
3045
  case 3: return obj[method](args[0],args[1],args[2]);
2717
3046
  case 4: return obj[method](args[0],args[1],args[2],args[3]);
2718
3047
  case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
2719
- };
3048
+ }
2720
3049
  };
2721
3050
 
2722
3051
  FakeXMLHttpRequest.filters = [];
@@ -2755,7 +3084,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2755
3084
  if(xhr.readyState === FakeXMLHttpRequest.DONE) {
2756
3085
  copyAttrs(["responseXML"]);
2757
3086
  }
2758
- if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
3087
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
2759
3088
  };
2760
3089
  if(xhr.addEventListener) {
2761
3090
  for(var event in fakeXhr.eventListeners) {
@@ -2773,6 +3102,12 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2773
3102
  };
2774
3103
  FakeXMLHttpRequest.useFilters = false;
2775
3104
 
3105
+ function verifyRequestOpened(xhr) {
3106
+ if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
3107
+ throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
3108
+ }
3109
+ }
3110
+
2776
3111
  function verifyRequestSent(xhr) {
2777
3112
  if (xhr.readyState == FakeXMLHttpRequest.DONE) {
2778
3113
  throw new Error("Request done");
@@ -2836,6 +3171,10 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2836
3171
  case FakeXMLHttpRequest.DONE:
2837
3172
  this.dispatchEvent(new sinon.Event("load", false, false, this));
2838
3173
  this.dispatchEvent(new sinon.Event("loadend", false, false, this));
3174
+ this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
3175
+ if (supportsProgress) {
3176
+ this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
3177
+ }
2839
3178
  break;
2840
3179
  }
2841
3180
  },
@@ -2856,6 +3195,7 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2856
3195
 
2857
3196
  // Helps testing
2858
3197
  setResponseHeaders: function setResponseHeaders(headers) {
3198
+ verifyRequestOpened(this);
2859
3199
  this.responseHeaders = {};
2860
3200
 
2861
3201
  for (var header in headers) {
@@ -2911,6 +3251,9 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2911
3251
  this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
2912
3252
 
2913
3253
  this.dispatchEvent(new sinon.Event("abort", false, false, this));
3254
+
3255
+ this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
3256
+
2914
3257
  if (typeof this.onerror === "function") {
2915
3258
  this.onerror();
2916
3259
  }
@@ -2990,14 +3333,22 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
2990
3333
  },
2991
3334
 
2992
3335
  respond: function respond(status, headers, body) {
2993
- this.setResponseHeaders(headers || {});
2994
3336
  this.status = typeof status == "number" ? status : 200;
2995
3337
  this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
3338
+ this.setResponseHeaders(headers || {});
2996
3339
  this.setResponseBody(body || "");
2997
- if (typeof this.onload === "function"){
2998
- this.onload();
3340
+ },
3341
+
3342
+ uploadProgress: function uploadProgress(progressEventRaw) {
3343
+ if (supportsProgress) {
3344
+ this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
2999
3345
  }
3346
+ },
3000
3347
 
3348
+ uploadError: function uploadError(error) {
3349
+ if (supportsCustomEvent) {
3350
+ this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
3351
+ }
3001
3352
  }
3002
3353
  });
3003
3354
 
@@ -3104,9 +3455,10 @@ sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
3104
3455
  };
3105
3456
 
3106
3457
  sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
3107
- })(this);
3108
3458
 
3109
- if (typeof module == "object" && typeof require == "function") {
3459
+ })((function(){ return typeof global === "object" ? global : this; })());
3460
+
3461
+ if (typeof module !== 'undefined' && module.exports) {
3110
3462
  module.exports = sinon;
3111
3463
  }
3112
3464
 
@@ -3168,7 +3520,6 @@ sinon.fakeServer = (function () {
3168
3520
  }
3169
3521
 
3170
3522
  function match(response, request) {
3171
- var requestMethod = this.getHTTPMethod(request);
3172
3523
  var requestUrl = request.url;
3173
3524
 
3174
3525
  if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
@@ -3178,7 +3529,7 @@ sinon.fakeServer = (function () {
3178
3529
  if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
3179
3530
  if (typeof response.response == "function") {
3180
3531
  var ru = response.url;
3181
- var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
3532
+ var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
3182
3533
  return response.response.apply(response, args);
3183
3534
  }
3184
3535
 
@@ -3188,15 +3539,6 @@ sinon.fakeServer = (function () {
3188
3539
  return false;
3189
3540
  }
3190
3541
 
3191
- function log(response, request) {
3192
- var str;
3193
-
3194
- str = "Request:\n" + sinon.format(request) + "\n\n";
3195
- str += "Response:\n" + sinon.format(response) + "\n\n";
3196
-
3197
- sinon.log(str);
3198
- }
3199
-
3200
3542
  return {
3201
3543
  create: function () {
3202
3544
  var server = create(this);
@@ -3216,16 +3558,16 @@ sinon.fakeServer = (function () {
3216
3558
 
3217
3559
  xhrObj.onSend = function () {
3218
3560
  server.handleRequest(this);
3219
- };
3220
3561
 
3221
- if (this.autoRespond && !this.responding) {
3222
- setTimeout(function () {
3223
- server.responding = false;
3224
- server.respond();
3225
- }, this.autoRespondAfter || 10);
3562
+ if (server.autoRespond && !server.responding) {
3563
+ setTimeout(function () {
3564
+ server.responding = false;
3565
+ server.respond();
3566
+ }, server.autoRespondAfter || 10);
3226
3567
 
3227
- this.responding = true;
3228
- }
3568
+ server.responding = true;
3569
+ }
3570
+ };
3229
3571
  },
3230
3572
 
3231
3573
  getHTTPMethod: function getHTTPMethod(request) {
@@ -3249,6 +3591,15 @@ sinon.fakeServer = (function () {
3249
3591
  }
3250
3592
  },
3251
3593
 
3594
+ log: function(response, request) {
3595
+ var str;
3596
+
3597
+ str = "Request:\n" + sinon.format(request) + "\n\n";
3598
+ str += "Response:\n" + sinon.format(response) + "\n\n";
3599
+
3600
+ sinon.log(str);
3601
+ },
3602
+
3252
3603
  respondWith: function respondWith(method, url, body) {
3253
3604
  if (arguments.length == 1 && typeof method != "function") {
3254
3605
  this.response = responseArray(method);
@@ -3278,9 +3629,10 @@ sinon.fakeServer = (function () {
3278
3629
  respond: function respond() {
3279
3630
  if (arguments.length > 0) this.respondWith.apply(this, arguments);
3280
3631
  var queue = this.queue || [];
3632
+ var requests = queue.splice(0, queue.length);
3281
3633
  var request;
3282
3634
 
3283
- while(request = queue.shift()) {
3635
+ while(request = requests.shift()) {
3284
3636
  this.processRequest(request);
3285
3637
  }
3286
3638
  },
@@ -3294,7 +3646,7 @@ sinon.fakeServer = (function () {
3294
3646
  var response = this.response || [404, {}, ""];
3295
3647
 
3296
3648
  if (this.responses) {
3297
- for (var i = 0, l = this.responses.length; i < l; i++) {
3649
+ for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
3298
3650
  if (match.call(this, this.responses[i], request)) {
3299
3651
  response = this.responses[i].response;
3300
3652
  break;
@@ -3303,7 +3655,7 @@ sinon.fakeServer = (function () {
3303
3655
  }
3304
3656
 
3305
3657
  if (request.readyState != 4) {
3306
- log(response, request);
3658
+ sinon.fakeServer.log(response, request);
3307
3659
 
3308
3660
  request.respond(response[0], response[1], response[2]);
3309
3661
  }
@@ -3318,7 +3670,7 @@ sinon.fakeServer = (function () {
3318
3670
  };
3319
3671
  }());
3320
3672
 
3321
- if (typeof module == "object" && typeof require == "function") {
3673
+ if (typeof module !== 'undefined' && module.exports) {
3322
3674
  module.exports = sinon;
3323
3675
  }
3324
3676
 
@@ -3423,7 +3775,7 @@ if (typeof module == "object" && typeof require == "function") {
3423
3775
  * Copyright (c) 2010-2013 Christian Johansen
3424
3776
  */
3425
3777
 
3426
- if (typeof module == "object" && typeof require == "function") {
3778
+ if (typeof module !== "undefined" && module.exports && typeof require == "function") {
3427
3779
  var sinon = require("../sinon");
3428
3780
  sinon.extend(sinon, require("./util/fake_timers"));
3429
3781
  }
@@ -3436,8 +3788,9 @@ if (typeof module == "object" && typeof require == "function") {
3436
3788
  return;
3437
3789
  }
3438
3790
 
3439
- if (config.injectInto) {
3791
+ if (config.injectInto && !(key in config.injectInto)) {
3440
3792
  config.injectInto[key] = value;
3793
+ sandbox.injectedKeys.push(key);
3441
3794
  } else {
3442
3795
  push.call(sandbox.args, value);
3443
3796
  }
@@ -3500,6 +3853,20 @@ if (typeof module == "object" && typeof require == "function") {
3500
3853
  return obj;
3501
3854
  },
3502
3855
 
3856
+ restore: function () {
3857
+ sinon.collection.restore.apply(this, arguments);
3858
+ this.restoreContext();
3859
+ },
3860
+
3861
+ restoreContext: function () {
3862
+ if (this.injectedKeys) {
3863
+ for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
3864
+ delete this.injectInto[this.injectedKeys[i]];
3865
+ }
3866
+ this.injectedKeys = [];
3867
+ }
3868
+ },
3869
+
3503
3870
  create: function (config) {
3504
3871
  if (!config) {
3505
3872
  return sinon.create(sinon.sandbox);
@@ -3507,6 +3874,8 @@ if (typeof module == "object" && typeof require == "function") {
3507
3874
 
3508
3875
  var sandbox = prepareSandboxFromConfig(config);
3509
3876
  sandbox.args = sandbox.args || [];
3877
+ sandbox.injectedKeys = [];
3878
+ sandbox.injectInto = config.injectInto;
3510
3879
  var prop, value, exposed = sandbox.inject({});
3511
3880
 
3512
3881
  if (config.properties) {
@@ -3525,7 +3894,9 @@ if (typeof module == "object" && typeof require == "function") {
3525
3894
 
3526
3895
  sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
3527
3896
 
3528
- if (typeof module == "object" && typeof require == "function") {
3897
+ if (typeof define === "function" && define.amd) {
3898
+ define(["module"], function(module) { module.exports = sinon.sandbox; });
3899
+ } else if (typeof module !== 'undefined' && module.exports) {
3529
3900
  module.exports = sinon.sandbox;
3530
3901
  }
3531
3902
  }());
@@ -3548,7 +3919,7 @@ if (typeof module == "object" && typeof require == "function") {
3548
3919
  */
3549
3920
 
3550
3921
  (function (sinon) {
3551
- var commonJSModule = typeof module == "object" && typeof require == "function";
3922
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
3552
3923
 
3553
3924
  if (!sinon && commonJSModule) {
3554
3925
  sinon = require("../sinon");
@@ -3565,7 +3936,7 @@ if (typeof module == "object" && typeof require == "function") {
3565
3936
  throw new TypeError("sinon.test needs to wrap a test function, got " + type);
3566
3937
  }
3567
3938
 
3568
- return function () {
3939
+ function sinonSandboxedTest() {
3569
3940
  var config = sinon.getConfig(sinon.config);
3570
3941
  config.injectInto = config.injectIntoThis && this || config.injectInto;
3571
3942
  var sandbox = sinon.sandbox.create(config);
@@ -3588,6 +3959,14 @@ if (typeof module == "object" && typeof require == "function") {
3588
3959
 
3589
3960
  return result;
3590
3961
  };
3962
+
3963
+ if (callback.length) {
3964
+ return function sinonAsyncSandboxedTest(callback) {
3965
+ return sinonSandboxedTest.apply(this, arguments);
3966
+ };
3967
+ }
3968
+
3969
+ return sinonSandboxedTest;
3591
3970
  }
3592
3971
 
3593
3972
  test.config = {
@@ -3598,10 +3977,12 @@ if (typeof module == "object" && typeof require == "function") {
3598
3977
  useFakeServer: true
3599
3978
  };
3600
3979
 
3601
- if (commonJSModule) {
3980
+ sinon.test = test;
3981
+
3982
+ if (typeof define === "function" && define.amd) {
3983
+ define(["module"], function(module) { module.exports = test; });
3984
+ } else if (commonJSModule) {
3602
3985
  module.exports = test;
3603
- } else {
3604
- sinon.test = test;
3605
3986
  }
3606
3987
  }(typeof sinon == "object" && sinon || null));
3607
3988
 
@@ -3621,7 +4002,7 @@ if (typeof module == "object" && typeof require == "function") {
3621
4002
  */
3622
4003
 
3623
4004
  (function (sinon) {
3624
- var commonJSModule = typeof module == "object" && typeof require == "function";
4005
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
3625
4006
 
3626
4007
  if (!sinon && commonJSModule) {
3627
4008
  sinon = require("../sinon");
@@ -3695,10 +4076,12 @@ if (typeof module == "object" && typeof require == "function") {
3695
4076
  return methods;
3696
4077
  }
3697
4078
 
3698
- if (commonJSModule) {
4079
+ sinon.testCase = testCase;
4080
+
4081
+ if (typeof define === "function" && define.amd) {
4082
+ define(["module"], function(module) { module.exports = testCase; });
4083
+ } else if (commonJSModule) {
3699
4084
  module.exports = testCase;
3700
- } else {
3701
- sinon.testCase = testCase;
3702
4085
  }
3703
4086
  }(typeof sinon == "object" && sinon || null));
3704
4087
 
@@ -3718,7 +4101,7 @@ if (typeof module == "object" && typeof require == "function") {
3718
4101
  */
3719
4102
 
3720
4103
  (function (sinon, global) {
3721
- var commonJSModule = typeof module == "object" && typeof require == "function";
4104
+ var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
3722
4105
  var slice = Array.prototype.slice;
3723
4106
  var assert;
3724
4107
 
@@ -3786,7 +4169,7 @@ if (typeof module == "object" && typeof require == "function") {
3786
4169
  function exposedName(prefix, prop) {
3787
4170
  return !prefix || /^fail/.test(prop) ? prop :
3788
4171
  prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
3789
- };
4172
+ }
3790
4173
 
3791
4174
  assert = {
3792
4175
  failException: "AssertError",
@@ -3854,6 +4237,20 @@ if (typeof module == "object" && typeof require == "function") {
3854
4237
  }
3855
4238
 
3856
4239
  return target;
4240
+ },
4241
+
4242
+ match: function match(actual, expectation) {
4243
+ var matcher = sinon.match(expectation);
4244
+ if (matcher.test(actual)) {
4245
+ assert.pass("match");
4246
+ } else {
4247
+ var formatted = [
4248
+ "expected value to match",
4249
+ " expected = " + sinon.format(expectation),
4250
+ " actual = " + sinon.format(actual)
4251
+ ]
4252
+ failAssertion(this, formatted.join("\n"));
4253
+ }
3857
4254
  }
3858
4255
  };
3859
4256
 
@@ -3878,10 +4275,218 @@ if (typeof module == "object" && typeof require == "function") {
3878
4275
  mirrorPropAsAssertion("threw", "%n did not throw exception%C");
3879
4276
  mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
3880
4277
 
3881
- if (commonJSModule) {
4278
+ sinon.assert = assert;
4279
+
4280
+ if (typeof define === "function" && define.amd) {
4281
+ define(["module"], function(module) { module.exports = assert; });
4282
+ } else if (commonJSModule) {
3882
4283
  module.exports = assert;
3883
- } else {
3884
- sinon.assert = assert;
3885
4284
  }
3886
4285
  }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
3887
4286
 
4287
+ /**
4288
+ * @depend ../../sinon.js
4289
+ * @depend event.js
4290
+ */
4291
+ /*jslint eqeqeq: false, onevar: false*/
4292
+ /*global sinon, module, require, XDomainRequest*/
4293
+ /**
4294
+ * Fake XDomainRequest object
4295
+ */
4296
+
4297
+ if (typeof sinon == "undefined") {
4298
+ this.sinon = {};
4299
+ }
4300
+ sinon.xdr = { XDomainRequest: this.XDomainRequest };
4301
+
4302
+ // wrapper for global
4303
+ (function (global) {
4304
+ var xdr = sinon.xdr;
4305
+ xdr.GlobalXDomainRequest = global.XDomainRequest;
4306
+ xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
4307
+ xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false;
4308
+
4309
+ function FakeXDomainRequest() {
4310
+ this.readyState = FakeXDomainRequest.UNSENT;
4311
+ this.requestBody = null;
4312
+ this.requestHeaders = {};
4313
+ this.status = 0;
4314
+ this.timeout = null;
4315
+
4316
+ if (typeof FakeXDomainRequest.onCreate == "function") {
4317
+ FakeXDomainRequest.onCreate(this);
4318
+ }
4319
+ }
4320
+
4321
+ function verifyState(xdr) {
4322
+ if (xdr.readyState !== FakeXDomainRequest.OPENED) {
4323
+ throw new Error("INVALID_STATE_ERR");
4324
+ }
4325
+
4326
+ if (xdr.sendFlag) {
4327
+ throw new Error("INVALID_STATE_ERR");
4328
+ }
4329
+ }
4330
+
4331
+ function verifyRequestSent(xdr) {
4332
+ if (xdr.readyState == FakeXDomainRequest.UNSENT) {
4333
+ throw new Error("Request not sent");
4334
+ }
4335
+ if (xdr.readyState == FakeXDomainRequest.DONE) {
4336
+ throw new Error("Request done");
4337
+ }
4338
+ }
4339
+
4340
+ function verifyResponseBodyType(body) {
4341
+ if (typeof body != "string") {
4342
+ var error = new Error("Attempted to respond to fake XDomainRequest with " +
4343
+ body + ", which is not a string.");
4344
+ error.name = "InvalidBodyException";
4345
+ throw error;
4346
+ }
4347
+ }
4348
+
4349
+ sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
4350
+ open: function open(method, url) {
4351
+ this.method = method;
4352
+ this.url = url;
4353
+
4354
+ this.responseText = null;
4355
+ this.sendFlag = false;
4356
+
4357
+ this.readyStateChange(FakeXDomainRequest.OPENED);
4358
+ },
4359
+
4360
+ readyStateChange: function readyStateChange(state) {
4361
+ this.readyState = state;
4362
+ var eventName = '';
4363
+ switch (this.readyState) {
4364
+ case FakeXDomainRequest.UNSENT:
4365
+ break;
4366
+ case FakeXDomainRequest.OPENED:
4367
+ break;
4368
+ case FakeXDomainRequest.LOADING:
4369
+ if (this.sendFlag){
4370
+ //raise the progress event
4371
+ eventName = 'onprogress';
4372
+ }
4373
+ break;
4374
+ case FakeXDomainRequest.DONE:
4375
+ if (this.isTimeout){
4376
+ eventName = 'ontimeout'
4377
+ }
4378
+ else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
4379
+ eventName = 'onerror';
4380
+ }
4381
+ else {
4382
+ eventName = 'onload'
4383
+ }
4384
+ break;
4385
+ }
4386
+
4387
+ // raising event (if defined)
4388
+ if (eventName) {
4389
+ if (typeof this[eventName] == "function") {
4390
+ try {
4391
+ this[eventName]();
4392
+ } catch (e) {
4393
+ sinon.logError("Fake XHR " + eventName + " handler", e);
4394
+ }
4395
+ }
4396
+ }
4397
+ },
4398
+
4399
+ send: function send(data) {
4400
+ verifyState(this);
4401
+
4402
+ if (!/^(get|head)$/i.test(this.method)) {
4403
+ this.requestBody = data;
4404
+ }
4405
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
4406
+
4407
+ this.errorFlag = false;
4408
+ this.sendFlag = true;
4409
+ this.readyStateChange(FakeXDomainRequest.OPENED);
4410
+
4411
+ if (typeof this.onSend == "function") {
4412
+ this.onSend(this);
4413
+ }
4414
+ },
4415
+
4416
+ abort: function abort() {
4417
+ this.aborted = true;
4418
+ this.responseText = null;
4419
+ this.errorFlag = true;
4420
+
4421
+ if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
4422
+ this.readyStateChange(sinon.FakeXDomainRequest.DONE);
4423
+ this.sendFlag = false;
4424
+ }
4425
+ },
4426
+
4427
+ setResponseBody: function setResponseBody(body) {
4428
+ verifyRequestSent(this);
4429
+ verifyResponseBodyType(body);
4430
+
4431
+ var chunkSize = this.chunkSize || 10;
4432
+ var index = 0;
4433
+ this.responseText = "";
4434
+
4435
+ do {
4436
+ this.readyStateChange(FakeXDomainRequest.LOADING);
4437
+ this.responseText += body.substring(index, index + chunkSize);
4438
+ index += chunkSize;
4439
+ } while (index < body.length);
4440
+
4441
+ this.readyStateChange(FakeXDomainRequest.DONE);
4442
+ },
4443
+
4444
+ respond: function respond(status, contentType, body) {
4445
+ // content-type ignored, since XDomainRequest does not carry this
4446
+ // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
4447
+ // test integration across browsers
4448
+ this.status = typeof status == "number" ? status : 200;
4449
+ this.setResponseBody(body || "");
4450
+ },
4451
+
4452
+ simulatetimeout: function(){
4453
+ this.status = 0;
4454
+ this.isTimeout = true;
4455
+ // Access to this should actually throw an error
4456
+ this.responseText = undefined;
4457
+ this.readyStateChange(FakeXDomainRequest.DONE);
4458
+ }
4459
+ });
4460
+
4461
+ sinon.extend(FakeXDomainRequest, {
4462
+ UNSENT: 0,
4463
+ OPENED: 1,
4464
+ LOADING: 3,
4465
+ DONE: 4
4466
+ });
4467
+
4468
+ sinon.useFakeXDomainRequest = function () {
4469
+ sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
4470
+ if (xdr.supportsXDR) {
4471
+ global.XDomainRequest = xdr.GlobalXDomainRequest;
4472
+ }
4473
+
4474
+ delete sinon.FakeXDomainRequest.restore;
4475
+
4476
+ if (keepOnCreate !== true) {
4477
+ delete sinon.FakeXDomainRequest.onCreate;
4478
+ }
4479
+ };
4480
+ if (xdr.supportsXDR) {
4481
+ global.XDomainRequest = sinon.FakeXDomainRequest;
4482
+ }
4483
+ return sinon.FakeXDomainRequest;
4484
+ };
4485
+
4486
+ sinon.FakeXDomainRequest = FakeXDomainRequest;
4487
+ })(this);
4488
+
4489
+ if (typeof module == "object" && typeof require == "function") {
4490
+ module.exports = sinon;
4491
+ }
4492
+