konacha-chai-matchers 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+