0
|
1 /**
|
|
2 * Sinon.JS 1.12.1, 2014/11/16
|
|
3 *
|
|
4 * @author Christian Johansen ([email protected])
|
|
5 * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
|
|
6 *
|
|
7 * (The BSD License)
|
|
8 *
|
|
9 * Copyright (c) 2010-2014, Christian Johansen, [email protected]
|
|
10 * All rights reserved.
|
|
11 *
|
|
12 * Redistribution and use in source and binary forms, with or without modification,
|
|
13 * are permitted provided that the following conditions are met:
|
|
14 *
|
|
15 * * Redistributions of source code must retain the above copyright notice,
|
|
16 * this list of conditions and the following disclaimer.
|
|
17 * * Redistributions in binary form must reproduce the above copyright notice,
|
|
18 * this list of conditions and the following disclaimer in the documentation
|
|
19 * and/or other materials provided with the distribution.
|
|
20 * * Neither the name of Christian Johansen nor the names of his contributors
|
|
21 * may be used to endorse or promote products derived from this software
|
|
22 * without specific prior written permission.
|
|
23 *
|
|
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34 */
|
|
35
|
|
36 (function (root, factory) {
|
|
37 if (typeof define === 'function' && define.amd) {
|
|
38 define([], function () {
|
|
39 return (root.sinon = factory());
|
|
40 });
|
|
41 } else if (typeof exports === 'object') {
|
|
42 module.exports = factory();
|
|
43 } else {
|
|
44 root.sinon = factory();
|
|
45 }
|
|
46 }(this, function () {
|
|
47 var samsam, formatio;
|
|
48 (function () {
|
|
49 function define(mod, deps, fn) {
|
|
50 if (mod == "samsam") {
|
|
51 samsam = deps();
|
|
52 } else if (typeof deps === "function" && mod.length === 0) {
|
|
53 lolex = deps();
|
|
54 } else if (typeof fn === "function") {
|
|
55 formatio = fn(samsam);
|
|
56 }
|
|
57 }
|
|
58 define.amd = {};
|
|
59 ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
|
|
60 (typeof module === "object" &&
|
|
61 function (m) { module.exports = m(); }) || // Node
|
|
62 function (m) { this.samsam = m(); } // Browser globals
|
|
63 )(function () {
|
|
64 var o = Object.prototype;
|
|
65 var div = typeof document !== "undefined" && document.createElement("div");
|
|
66
|
|
67 function isNaN(value) {
|
|
68 // Unlike global isNaN, this avoids type coercion
|
|
69 // typeof check avoids IE host object issues, hat tip to
|
|
70 // lodash
|
|
71 var val = value; // JsLint thinks value !== value is "weird"
|
|
72 return typeof value === "number" && value !== val;
|
|
73 }
|
|
74
|
|
75 function getClass(value) {
|
|
76 // Returns the internal [[Class]] by calling Object.prototype.toString
|
|
77 // with the provided value as this. Return value is a string, naming the
|
|
78 // internal class, e.g. "Array"
|
|
79 return o.toString.call(value).split(/[ \]]/)[1];
|
|
80 }
|
|
81
|
|
82 /**
|
|
83 * @name samsam.isArguments
|
|
84 * @param Object object
|
|
85 *
|
|
86 * Returns ``true`` if ``object`` is an ``arguments`` object,
|
|
87 * ``false`` otherwise.
|
|
88 */
|
|
89 function isArguments(object) {
|
|
90 if (getClass(object) === 'Arguments') { return true; }
|
|
91 if (typeof object !== "object" || typeof object.length !== "number" ||
|
|
92 getClass(object) === "Array") {
|
|
93 return false;
|
|
94 }
|
|
95 if (typeof object.callee == "function") { return true; }
|
|
96 try {
|
|
97 object[object.length] = 6;
|
|
98 delete object[object.length];
|
|
99 } catch (e) {
|
|
100 return true;
|
|
101 }
|
|
102 return false;
|
|
103 }
|
|
104
|
|
105 /**
|
|
106 * @name samsam.isElement
|
|
107 * @param Object object
|
|
108 *
|
|
109 * Returns ``true`` if ``object`` is a DOM element node. Unlike
|
|
110 * Underscore.js/lodash, this function will return ``false`` if ``object``
|
|
111 * is an *element-like* object, i.e. a regular object with a ``nodeType``
|
|
112 * property that holds the value ``1``.
|
|
113 */
|
|
114 function isElement(object) {
|
|
115 if (!object || object.nodeType !== 1 || !div) { return false; }
|
|
116 try {
|
|
117 object.appendChild(div);
|
|
118 object.removeChild(div);
|
|
119 } catch (e) {
|
|
120 return false;
|
|
121 }
|
|
122 return true;
|
|
123 }
|
|
124
|
|
125 /**
|
|
126 * @name samsam.keys
|
|
127 * @param Object object
|
|
128 *
|
|
129 * Return an array of own property names.
|
|
130 */
|
|
131 function keys(object) {
|
|
132 var ks = [], prop;
|
|
133 for (prop in object) {
|
|
134 if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
|
|
135 }
|
|
136 return ks;
|
|
137 }
|
|
138
|
|
139 /**
|
|
140 * @name samsam.isDate
|
|
141 * @param Object value
|
|
142 *
|
|
143 * Returns true if the object is a ``Date``, or *date-like*. Duck typing
|
|
144 * of date objects work by checking that the object has a ``getTime``
|
|
145 * function whose return value equals the return value from the object's
|
|
146 * ``valueOf``.
|
|
147 */
|
|
148 function isDate(value) {
|
|
149 return typeof value.getTime == "function" &&
|
|
150 value.getTime() == value.valueOf();
|
|
151 }
|
|
152
|
|
153 /**
|
|
154 * @name samsam.isNegZero
|
|
155 * @param Object value
|
|
156 *
|
|
157 * Returns ``true`` if ``value`` is ``-0``.
|
|
158 */
|
|
159 function isNegZero(value) {
|
|
160 return value === 0 && 1 / value === -Infinity;
|
|
161 }
|
|
162
|
|
163 /**
|
|
164 * @name samsam.equal
|
|
165 * @param Object obj1
|
|
166 * @param Object obj2
|
|
167 *
|
|
168 * Returns ``true`` if two objects are strictly equal. Compared to
|
|
169 * ``===`` there are two exceptions:
|
|
170 *
|
|
171 * - NaN is considered equal to NaN
|
|
172 * - -0 and +0 are not considered equal
|
|
173 */
|
|
174 function identical(obj1, obj2) {
|
|
175 if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
|
|
176 return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
|
|
177 }
|
|
178 }
|
|
179
|
|
180
|
|
181 /**
|
|
182 * @name samsam.deepEqual
|
|
183 * @param Object obj1
|
|
184 * @param Object obj2
|
|
185 *
|
|
186 * Deep equal comparison. Two values are "deep equal" if:
|
|
187 *
|
|
188 * - They are equal, according to samsam.identical
|
|
189 * - They are both date objects representing the same time
|
|
190 * - They are both arrays containing elements that are all deepEqual
|
|
191 * - They are objects with the same set of properties, and each property
|
|
192 * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
|
|
193 *
|
|
194 * Supports cyclic objects.
|
|
195 */
|
|
196 function deepEqualCyclic(obj1, obj2) {
|
|
197
|
|
198 // used for cyclic comparison
|
|
199 // contain already visited objects
|
|
200 var objects1 = [],
|
|
201 objects2 = [],
|
|
202 // contain pathes (position in the object structure)
|
|
203 // of the already visited objects
|
|
204 // indexes same as in objects arrays
|
|
205 paths1 = [],
|
|
206 paths2 = [],
|
|
207 // contains combinations of already compared objects
|
|
208 // in the manner: { "$1['ref']$2['ref']": true }
|
|
209 compared = {};
|
|
210
|
|
211 /**
|
|
212 * used to check, if the value of a property is an object
|
|
213 * (cyclic logic is only needed for objects)
|
|
214 * only needed for cyclic logic
|
|
215 */
|
|
216 function isObject(value) {
|
|
217
|
|
218 if (typeof value === 'object' && value !== null &&
|
|
219 !(value instanceof Boolean) &&
|
|
220 !(value instanceof Date) &&
|
|
221 !(value instanceof Number) &&
|
|
222 !(value instanceof RegExp) &&
|
|
223 !(value instanceof String)) {
|
|
224
|
|
225 return true;
|
|
226 }
|
|
227
|
|
228 return false;
|
|
229 }
|
|
230
|
|
231 /**
|
|
232 * returns the index of the given object in the
|
|
233 * given objects array, -1 if not contained
|
|
234 * only needed for cyclic logic
|
|
235 */
|
|
236 function getIndex(objects, obj) {
|
|
237
|
|
238 var i;
|
|
239 for (i = 0; i < objects.length; i++) {
|
|
240 if (objects[i] === obj) {
|
|
241 return i;
|
|
242 }
|
|
243 }
|
|
244
|
|
245 return -1;
|
|
246 }
|
|
247
|
|
248 // does the recursion for the deep equal check
|
|
249 return (function deepEqual(obj1, obj2, path1, path2) {
|
|
250 var type1 = typeof obj1;
|
|
251 var type2 = typeof obj2;
|
|
252
|
|
253 // == null also matches undefined
|
|
254 if (obj1 === obj2 ||
|
|
255 isNaN(obj1) || isNaN(obj2) ||
|
|
256 obj1 == null || obj2 == null ||
|
|
257 type1 !== "object" || type2 !== "object") {
|
|
258
|
|
259 return identical(obj1, obj2);
|
|
260 }
|
|
261
|
|
262 // Elements are only equal if identical(expected, actual)
|
|
263 if (isElement(obj1) || isElement(obj2)) { return false; }
|
|
264
|
|
265 var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
|
|
266 if (isDate1 || isDate2) {
|
|
267 if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
|
|
268 return false;
|
|
269 }
|
|
270 }
|
|
271
|
|
272 if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
|
|
273 if (obj1.toString() !== obj2.toString()) { return false; }
|
|
274 }
|
|
275
|
|
276 var class1 = getClass(obj1);
|
|
277 var class2 = getClass(obj2);
|
|
278 var keys1 = keys(obj1);
|
|
279 var keys2 = keys(obj2);
|
|
280
|
|
281 if (isArguments(obj1) || isArguments(obj2)) {
|
|
282 if (obj1.length !== obj2.length) { return false; }
|
|
283 } else {
|
|
284 if (type1 !== type2 || class1 !== class2 ||
|
|
285 keys1.length !== keys2.length) {
|
|
286 return false;
|
|
287 }
|
|
288 }
|
|
289
|
|
290 var key, i, l,
|
|
291 // following vars are used for the cyclic logic
|
|
292 value1, value2,
|
|
293 isObject1, isObject2,
|
|
294 index1, index2,
|
|
295 newPath1, newPath2;
|
|
296
|
|
297 for (i = 0, l = keys1.length; i < l; i++) {
|
|
298 key = keys1[i];
|
|
299 if (!o.hasOwnProperty.call(obj2, key)) {
|
|
300 return false;
|
|
301 }
|
|
302
|
|
303 // Start of the cyclic logic
|
|
304
|
|
305 value1 = obj1[key];
|
|
306 value2 = obj2[key];
|
|
307
|
|
308 isObject1 = isObject(value1);
|
|
309 isObject2 = isObject(value2);
|
|
310
|
|
311 // determine, if the objects were already visited
|
|
312 // (it's faster to check for isObject first, than to
|
|
313 // get -1 from getIndex for non objects)
|
|
314 index1 = isObject1 ? getIndex(objects1, value1) : -1;
|
|
315 index2 = isObject2 ? getIndex(objects2, value2) : -1;
|
|
316
|
|
317 // determine the new pathes of the objects
|
|
318 // - for non cyclic objects the current path will be extended
|
|
319 // by current property name
|
|
320 // - for cyclic objects the stored path is taken
|
|
321 newPath1 = index1 !== -1
|
|
322 ? paths1[index1]
|
|
323 : path1 + '[' + JSON.stringify(key) + ']';
|
|
324 newPath2 = index2 !== -1
|
|
325 ? paths2[index2]
|
|
326 : path2 + '[' + JSON.stringify(key) + ']';
|
|
327
|
|
328 // stop recursion if current objects are already compared
|
|
329 if (compared[newPath1 + newPath2]) {
|
|
330 return true;
|
|
331 }
|
|
332
|
|
333 // remember the current objects and their pathes
|
|
334 if (index1 === -1 && isObject1) {
|
|
335 objects1.push(value1);
|
|
336 paths1.push(newPath1);
|
|
337 }
|
|
338 if (index2 === -1 && isObject2) {
|
|
339 objects2.push(value2);
|
|
340 paths2.push(newPath2);
|
|
341 }
|
|
342
|
|
343 // remember that the current objects are already compared
|
|
344 if (isObject1 && isObject2) {
|
|
345 compared[newPath1 + newPath2] = true;
|
|
346 }
|
|
347
|
|
348 // End of cyclic logic
|
|
349
|
|
350 // neither value1 nor value2 is a cycle
|
|
351 // continue with next level
|
|
352 if (!deepEqual(value1, value2, newPath1, newPath2)) {
|
|
353 return false;
|
|
354 }
|
|
355 }
|
|
356
|
|
357 return true;
|
|
358
|
|
359 }(obj1, obj2, '$1', '$2'));
|
|
360 }
|
|
361
|
|
362 var match;
|
|
363
|
|
364 function arrayContains(array, subset) {
|
|
365 if (subset.length === 0) { return true; }
|
|
366 var i, l, j, k;
|
|
367 for (i = 0, l = array.length; i < l; ++i) {
|
|
368 if (match(array[i], subset[0])) {
|
|
369 for (j = 0, k = subset.length; j < k; ++j) {
|
|
370 if (!match(array[i + j], subset[j])) { return false; }
|
|
371 }
|
|
372 return true;
|
|
373 }
|
|
374 }
|
|
375 return false;
|
|
376 }
|
|
377
|
|
378 /**
|
|
379 * @name samsam.match
|
|
380 * @param Object object
|
|
381 * @param Object matcher
|
|
382 *
|
|
383 * Compare arbitrary value ``object`` with matcher.
|
|
384 */
|
|
385 match = function match(object, matcher) {
|
|
386 if (matcher && typeof matcher.test === "function") {
|
|
387 return matcher.test(object);
|
|
388 }
|
|
389
|
|
390 if (typeof matcher === "function") {
|
|
391 return matcher(object) === true;
|
|
392 }
|
|
393
|
|
394 if (typeof matcher === "string") {
|
|
395 matcher = matcher.toLowerCase();
|
|
396 var notNull = typeof object === "string" || !!object;
|
|
397 return notNull &&
|
|
398 (String(object)).toLowerCase().indexOf(matcher) >= 0;
|
|
399 }
|
|
400
|
|
401 if (typeof matcher === "number") {
|
|
402 return matcher === object;
|
|
403 }
|
|
404
|
|
405 if (typeof matcher === "boolean") {
|
|
406 return matcher === object;
|
|
407 }
|
|
408
|
|
409 if (getClass(object) === "Array" && getClass(matcher) === "Array") {
|
|
410 return arrayContains(object, matcher);
|
|
411 }
|
|
412
|
|
413 if (matcher && typeof matcher === "object") {
|
|
414 var prop;
|
|
415 for (prop in matcher) {
|
|
416 var value = object[prop];
|
|
417 if (typeof value === "undefined" &&
|
|
418 typeof object.getAttribute === "function") {
|
|
419 value = object.getAttribute(prop);
|
|
420 }
|
|
421 if (typeof value === "undefined" || !match(value, matcher[prop])) {
|
|
422 return false;
|
|
423 }
|
|
424 }
|
|
425 return true;
|
|
426 }
|
|
427
|
|
428 throw new Error("Matcher was not a string, a number, a " +
|
|
429 "function, a boolean or an object");
|
|
430 };
|
|
431
|
|
432 return {
|
|
433 isArguments: isArguments,
|
|
434 isElement: isElement,
|
|
435 isDate: isDate,
|
|
436 isNegZero: isNegZero,
|
|
437 identical: identical,
|
|
438 deepEqual: deepEqualCyclic,
|
|
439 match: match,
|
|
440 keys: keys
|
|
441 };
|
|
442 });
|
|
443 ((typeof define === "function" && define.amd && function (m) {
|
|
444 define("formatio", ["samsam"], m);
|
|
445 }) || (typeof module === "object" && function (m) {
|
|
446 module.exports = m(require("samsam"));
|
|
447 }) || function (m) { this.formatio = m(this.samsam); }
|
|
448 )(function (samsam) {
|
|
449
|
|
450 var formatio = {
|
|
451 excludeConstructors: ["Object", /^.$/],
|
|
452 quoteStrings: true,
|
|
453 limitChildrenCount: 0
|
|
454 };
|
|
455
|
|
456 var hasOwn = Object.prototype.hasOwnProperty;
|
|
457
|
|
458 var specialObjects = [];
|
|
459 if (typeof global !== "undefined") {
|
|
460 specialObjects.push({ object: global, value: "[object global]" });
|
|
461 }
|
|
462 if (typeof document !== "undefined") {
|
|
463 specialObjects.push({
|
|
464 object: document,
|
|
465 value: "[object HTMLDocument]"
|
|
466 });
|
|
467 }
|
|
468 if (typeof window !== "undefined") {
|
|
469 specialObjects.push({ object: window, value: "[object Window]" });
|
|
470 }
|
|
471
|
|
472 function functionName(func) {
|
|
473 if (!func) { return ""; }
|
|
474 if (func.displayName) { return func.displayName; }
|
|
475 if (func.name) { return func.name; }
|
|
476 var matches = func.toString().match(/function\s+([^\(]+)/m);
|
|
477 return (matches && matches[1]) || "";
|
|
478 }
|
|
479
|
|
480 function constructorName(f, object) {
|
|
481 var name = functionName(object && object.constructor);
|
|
482 var excludes = f.excludeConstructors ||
|
|
483 formatio.excludeConstructors || [];
|
|
484
|
|
485 var i, l;
|
|
486 for (i = 0, l = excludes.length; i < l; ++i) {
|
|
487 if (typeof excludes[i] === "string" && excludes[i] === name) {
|
|
488 return "";
|
|
489 } else if (excludes[i].test && excludes[i].test(name)) {
|
|
490 return "";
|
|
491 }
|
|
492 }
|
|
493
|
|
494 return name;
|
|
495 }
|
|
496
|
|
497 function isCircular(object, objects) {
|
|
498 if (typeof object !== "object") { return false; }
|
|
499 var i, l;
|
|
500 for (i = 0, l = objects.length; i < l; ++i) {
|
|
501 if (objects[i] === object) { return true; }
|
|
502 }
|
|
503 return false;
|
|
504 }
|
|
505
|
|
506 function ascii(f, object, processed, indent) {
|
|
507 if (typeof object === "string") {
|
|
508 var qs = f.quoteStrings;
|
|
509 var quote = typeof qs !== "boolean" || qs;
|
|
510 return processed || quote ? '"' + object + '"' : object;
|
|
511 }
|
|
512
|
|
513 if (typeof object === "function" && !(object instanceof RegExp)) {
|
|
514 return ascii.func(object);
|
|
515 }
|
|
516
|
|
517 processed = processed || [];
|
|
518
|
|
519 if (isCircular(object, processed)) { return "[Circular]"; }
|
|
520
|
|
521 if (Object.prototype.toString.call(object) === "[object Array]") {
|
|
522 return ascii.array.call(f, object, processed);
|
|
523 }
|
|
524
|
|
525 if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
|
|
526 if (samsam.isElement(object)) { return ascii.element(object); }
|
|
527
|
|
528 if (typeof object.toString === "function" &&
|
|
529 object.toString !== Object.prototype.toString) {
|
|
530 return object.toString();
|
|
531 }
|
|
532
|
|
533 var i, l;
|
|
534 for (i = 0, l = specialObjects.length; i < l; i++) {
|
|
535 if (object === specialObjects[i].object) {
|
|
536 return specialObjects[i].value;
|
|
537 }
|
|
538 }
|
|
539
|
|
540 return ascii.object.call(f, object, processed, indent);
|
|
541 }
|
|
542
|
|
543 ascii.func = function (func) {
|
|
544 return "function " + functionName(func) + "() {}";
|
|
545 };
|
|
546
|
|
547 ascii.array = function (array, processed) {
|
|
548 processed = processed || [];
|
|
549 processed.push(array);
|
|
550 var pieces = [];
|
|
551 var i, l;
|
|
552 l = (this.limitChildrenCount > 0) ?
|
|
553 Math.min(this.limitChildrenCount, array.length) : array.length;
|
|
554
|
|
555 for (i = 0; i < l; ++i) {
|
|
556 pieces.push(ascii(this, array[i], processed));
|
|
557 }
|
|
558
|
|
559 if(l < array.length)
|
|
560 pieces.push("[... " + (array.length - l) + " more elements]");
|
|
561
|
|
562 return "[" + pieces.join(", ") + "]";
|
|
563 };
|
|
564
|
|
565 ascii.object = function (object, processed, indent) {
|
|
566 processed = processed || [];
|
|
567 processed.push(object);
|
|
568 indent = indent || 0;
|
|
569 var pieces = [], properties = samsam.keys(object).sort();
|
|
570 var length = 3;
|
|
571 var prop, str, obj, i, k, l;
|
|
572 l = (this.limitChildrenCount > 0) ?
|
|
573 Math.min(this.limitChildrenCount, properties.length) : properties.length;
|
|
574
|
|
575 for (i = 0; i < l; ++i) {
|
|
576 prop = properties[i];
|
|
577 obj = object[prop];
|
|
578
|
|
579 if (isCircular(obj, processed)) {
|
|
580 str = "[Circular]";
|
|
581 } else {
|
|
582 str = ascii(this, obj, processed, indent + 2);
|
|
583 }
|
|
584
|
|
585 str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
|
|
586 length += str.length;
|
|
587 pieces.push(str);
|
|
588 }
|
|
589
|
|
590 var cons = constructorName(this, object);
|
|
591 var prefix = cons ? "[" + cons + "] " : "";
|
|
592 var is = "";
|
|
593 for (i = 0, k = indent; i < k; ++i) { is += " "; }
|
|
594
|
|
595 if(l < properties.length)
|
|
596 pieces.push("[... " + (properties.length - l) + " more elements]");
|
|
597
|
|
598 if (length + indent > 80) {
|
|
599 return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
|
|
600 is + "}";
|
|
601 }
|
|
602 return prefix + "{ " + pieces.join(", ") + " }";
|
|
603 };
|
|
604
|
|
605 ascii.element = function (element) {
|
|
606 var tagName = element.tagName.toLowerCase();
|
|
607 var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
|
|
608
|
|
609 for (i = 0, l = attrs.length; i < l; ++i) {
|
|
610 attr = attrs.item(i);
|
|
611 attrName = attr.nodeName.toLowerCase().replace("html:", "");
|
|
612 val = attr.nodeValue;
|
|
613 if (attrName !== "contenteditable" || val !== "inherit") {
|
|
614 if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
|
|
615 }
|
|
616 }
|
|
617
|
|
618 var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
|
|
619 var content = element.innerHTML;
|
|
620
|
|
621 if (content.length > 20) {
|
|
622 content = content.substr(0, 20) + "[...]";
|
|
623 }
|
|
624
|
|
625 var res = formatted + pairs.join(" ") + ">" + content +
|
|
626 "</" + tagName + ">";
|
|
627
|
|
628 return res.replace(/ contentEditable="inherit"/, "");
|
|
629 };
|
|
630
|
|
631 function Formatio(options) {
|
|
632 for (var opt in options) {
|
|
633 this[opt] = options[opt];
|
|
634 }
|
|
635 }
|
|
636
|
|
637 Formatio.prototype = {
|
|
638 functionName: functionName,
|
|
639
|
|
640 configure: function (options) {
|
|
641 return new Formatio(options);
|
|
642 },
|
|
643
|
|
644 constructorName: function (object) {
|
|
645 return constructorName(this, object);
|
|
646 },
|
|
647
|
|
648 ascii: function (object, processed, indent) {
|
|
649 return ascii(this, object, processed, indent);
|
|
650 }
|
|
651 };
|
|
652
|
|
653 return Formatio.prototype;
|
|
654 });
|
|
655 !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
656 (function (global){
|
|
657 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
|
|
658 /*global global*/
|
|
659 /**
|
|
660 * @author Christian Johansen ([email protected]) and contributors
|
|
661 * @license BSD
|
|
662 *
|
|
663 * Copyright (c) 2010-2014 Christian Johansen
|
|
664 */
|
|
665
|
|
666 // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
|
|
667 // browsers, a number.
|
|
668 // see https://github.com/cjohansen/Sinon.JS/pull/436
|
|
669 var timeoutResult = setTimeout(function() {}, 0);
|
|
670 var addTimerReturnsObject = typeof timeoutResult === "object";
|
|
671 clearTimeout(timeoutResult);
|
|
672
|
|
673 var NativeDate = Date;
|
|
674 var id = 1;
|
|
675
|
|
676 /**
|
|
677 * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
|
|
678 * number of milliseconds. This is used to support human-readable strings passed
|
|
679 * to clock.tick()
|
|
680 */
|
|
681 function parseTime(str) {
|
|
682 if (!str) {
|
|
683 return 0;
|
|
684 }
|
|
685
|
|
686 var strings = str.split(":");
|
|
687 var l = strings.length, i = l;
|
|
688 var ms = 0, parsed;
|
|
689
|
|
690 if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
|
|
691 throw new Error("tick only understands numbers and 'h:m:s'");
|
|
692 }
|
|
693
|
|
694 while (i--) {
|
|
695 parsed = parseInt(strings[i], 10);
|
|
696
|
|
697 if (parsed >= 60) {
|
|
698 throw new Error("Invalid time " + str);
|
|
699 }
|
|
700
|
|
701 ms += parsed * Math.pow(60, (l - i - 1));
|
|
702 }
|
|
703
|
|
704 return ms * 1000;
|
|
705 }
|
|
706
|
|
707 /**
|
|
708 * Used to grok the `now` parameter to createClock.
|
|
709 */
|
|
710 function getEpoch(epoch) {
|
|
711 if (!epoch) { return 0; }
|
|
712 if (typeof epoch.getTime === "function") { return epoch.getTime(); }
|
|
713 if (typeof epoch === "number") { return epoch; }
|
|
714 throw new TypeError("now should be milliseconds since UNIX epoch");
|
|
715 }
|
|
716
|
|
717 function inRange(from, to, timer) {
|
|
718 return timer && timer.callAt >= from && timer.callAt <= to;
|
|
719 }
|
|
720
|
|
721 function mirrorDateProperties(target, source) {
|
|
722 if (source.now) {
|
|
723 target.now = function now() {
|
|
724 return target.clock.now;
|
|
725 };
|
|
726 } else {
|
|
727 delete target.now;
|
|
728 }
|
|
729
|
|
730 if (source.toSource) {
|
|
731 target.toSource = function toSource() {
|
|
732 return source.toSource();
|
|
733 };
|
|
734 } else {
|
|
735 delete target.toSource;
|
|
736 }
|
|
737
|
|
738 target.toString = function toString() {
|
|
739 return source.toString();
|
|
740 };
|
|
741
|
|
742 target.prototype = source.prototype;
|
|
743 target.parse = source.parse;
|
|
744 target.UTC = source.UTC;
|
|
745 target.prototype.toUTCString = source.prototype.toUTCString;
|
|
746
|
|
747 for (var prop in source) {
|
|
748 if (source.hasOwnProperty(prop)) {
|
|
749 target[prop] = source[prop];
|
|
750 }
|
|
751 }
|
|
752
|
|
753 return target;
|
|
754 }
|
|
755
|
|
756 function createDate() {
|
|
757 function ClockDate(year, month, date, hour, minute, second, ms) {
|
|
758 // Defensive and verbose to avoid potential harm in passing
|
|
759 // explicit undefined when user does not pass argument
|
|
760 switch (arguments.length) {
|
|
761 case 0:
|
|
762 return new NativeDate(ClockDate.clock.now);
|
|
763 case 1:
|
|
764 return new NativeDate(year);
|
|
765 case 2:
|
|
766 return new NativeDate(year, month);
|
|
767 case 3:
|
|
768 return new NativeDate(year, month, date);
|
|
769 case 4:
|
|
770 return new NativeDate(year, month, date, hour);
|
|
771 case 5:
|
|
772 return new NativeDate(year, month, date, hour, minute);
|
|
773 case 6:
|
|
774 return new NativeDate(year, month, date, hour, minute, second);
|
|
775 default:
|
|
776 return new NativeDate(year, month, date, hour, minute, second, ms);
|
|
777 }
|
|
778 }
|
|
779
|
|
780 return mirrorDateProperties(ClockDate, NativeDate);
|
|
781 }
|
|
782
|
|
783 function addTimer(clock, timer) {
|
|
784 if (typeof timer.func === "undefined") {
|
|
785 throw new Error("Callback must be provided to timer calls");
|
|
786 }
|
|
787
|
|
788 if (!clock.timers) {
|
|
789 clock.timers = {};
|
|
790 }
|
|
791
|
|
792 timer.id = id++;
|
|
793 timer.createdAt = clock.now;
|
|
794 timer.callAt = clock.now + (timer.delay || 0);
|
|
795
|
|
796 clock.timers[timer.id] = timer;
|
|
797
|
|
798 if (addTimerReturnsObject) {
|
|
799 return {
|
|
800 id: timer.id,
|
|
801 ref: function() {},
|
|
802 unref: function() {}
|
|
803 };
|
|
804 }
|
|
805 else {
|
|
806 return timer.id;
|
|
807 }
|
|
808 }
|
|
809
|
|
810 function firstTimerInRange(clock, from, to) {
|
|
811 var timers = clock.timers, timer = null;
|
|
812
|
|
813 for (var id in timers) {
|
|
814 if (!inRange(from, to, timers[id])) {
|
|
815 continue;
|
|
816 }
|
|
817
|
|
818 if (!timer || ~compareTimers(timer, timers[id])) {
|
|
819 timer = timers[id];
|
|
820 }
|
|
821 }
|
|
822
|
|
823 return timer;
|
|
824 }
|
|
825
|
|
826 function compareTimers(a, b) {
|
|
827 // Sort first by absolute timing
|
|
828 if (a.callAt < b.callAt) {
|
|
829 return -1;
|
|
830 }
|
|
831 if (a.callAt > b.callAt) {
|
|
832 return 1;
|
|
833 }
|
|
834
|
|
835 // Sort next by immediate, immediate timers take precedence
|
|
836 if (a.immediate && !b.immediate) {
|
|
837 return -1;
|
|
838 }
|
|
839 if (!a.immediate && b.immediate) {
|
|
840 return 1;
|
|
841 }
|
|
842
|
|
843 // Sort next by creation time, earlier-created timers take precedence
|
|
844 if (a.createdAt < b.createdAt) {
|
|
845 return -1;
|
|
846 }
|
|
847 if (a.createdAt > b.createdAt) {
|
|
848 return 1;
|
|
849 }
|
|
850
|
|
851 // Sort next by id, lower-id timers take precedence
|
|
852 if (a.id < b.id) {
|
|
853 return -1;
|
|
854 }
|
|
855 if (a.id > b.id) {
|
|
856 return 1;
|
|
857 }
|
|
858
|
|
859 // As timer ids are unique, no fallback `0` is necessary
|
|
860 }
|
|
861
|
|
862 function callTimer(clock, timer) {
|
|
863 if (typeof timer.interval == "number") {
|
|
864 clock.timers[timer.id].callAt += timer.interval;
|
|
865 } else {
|
|
866 delete clock.timers[timer.id];
|
|
867 }
|
|
868
|
|
869 try {
|
|
870 if (typeof timer.func == "function") {
|
|
871 timer.func.apply(null, timer.args);
|
|
872 } else {
|
|
873 eval(timer.func);
|
|
874 }
|
|
875 } catch (e) {
|
|
876 var exception = e;
|
|
877 }
|
|
878
|
|
879 if (!clock.timers[timer.id]) {
|
|
880 if (exception) {
|
|
881 throw exception;
|
|
882 }
|
|
883 return;
|
|
884 }
|
|
885
|
|
886 if (exception) {
|
|
887 throw exception;
|
|
888 }
|
|
889 }
|
|
890
|
|
891 function uninstall(clock, target) {
|
|
892 var method;
|
|
893
|
|
894 for (var i = 0, l = clock.methods.length; i < l; i++) {
|
|
895 method = clock.methods[i];
|
|
896
|
|
897 if (target[method].hadOwnProperty) {
|
|
898 target[method] = clock["_" + method];
|
|
899 } else {
|
|
900 try {
|
|
901 delete target[method];
|
|
902 } catch (e) {}
|
|
903 }
|
|
904 }
|
|
905
|
|
906 // Prevent multiple executions which will completely remove these props
|
|
907 clock.methods = [];
|
|
908 }
|
|
909
|
|
910 function hijackMethod(target, method, clock) {
|
|
911 clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
|
|
912 clock["_" + method] = target[method];
|
|
913
|
|
914 if (method == "Date") {
|
|
915 var date = mirrorDateProperties(clock[method], target[method]);
|
|
916 target[method] = date;
|
|
917 } else {
|
|
918 target[method] = function () {
|
|
919 return clock[method].apply(clock, arguments);
|
|
920 };
|
|
921
|
|
922 for (var prop in clock[method]) {
|
|
923 if (clock[method].hasOwnProperty(prop)) {
|
|
924 target[method][prop] = clock[method][prop];
|
|
925 }
|
|
926 }
|
|
927 }
|
|
928
|
|
929 target[method].clock = clock;
|
|
930 }
|
|
931
|
|
932 var timers = {
|
|
933 setTimeout: setTimeout,
|
|
934 clearTimeout: clearTimeout,
|
|
935 setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
|
|
936 clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
|
|
937 setInterval: setInterval,
|
|
938 clearInterval: clearInterval,
|
|
939 Date: Date
|
|
940 };
|
|
941
|
|
942 var keys = Object.keys || function (obj) {
|
|
943 var ks = [];
|
|
944 for (var key in obj) {
|
|
945 ks.push(key);
|
|
946 }
|
|
947 return ks;
|
|
948 };
|
|
949
|
|
950 exports.timers = timers;
|
|
951
|
|
952 var createClock = exports.createClock = function (now) {
|
|
953 var clock = {
|
|
954 now: getEpoch(now),
|
|
955 timeouts: {},
|
|
956 Date: createDate()
|
|
957 };
|
|
958
|
|
959 clock.Date.clock = clock;
|
|
960
|
|
961 clock.setTimeout = function setTimeout(func, timeout) {
|
|
962 return addTimer(clock, {
|
|
963 func: func,
|
|
964 args: Array.prototype.slice.call(arguments, 2),
|
|
965 delay: timeout
|
|
966 });
|
|
967 };
|
|
968
|
|
969 clock.clearTimeout = function clearTimeout(timerId) {
|
|
970 if (!timerId) {
|
|
971 // null appears to be allowed in most browsers, and appears to be
|
|
972 // relied upon by some libraries, like Bootstrap carousel
|
|
973 return;
|
|
974 }
|
|
975 if (!clock.timers) {
|
|
976 clock.timers = [];
|
|
977 }
|
|
978 // in Node, timerId is an object with .ref()/.unref(), and
|
|
979 // its .id field is the actual timer id.
|
|
980 if (typeof timerId === "object") {
|
|
981 timerId = timerId.id
|
|
982 }
|
|
983 if (timerId in clock.timers) {
|
|
984 delete clock.timers[timerId];
|
|
985 }
|
|
986 };
|
|
987
|
|
988 clock.setInterval = function setInterval(func, timeout) {
|
|
989 return addTimer(clock, {
|
|
990 func: func,
|
|
991 args: Array.prototype.slice.call(arguments, 2),
|
|
992 delay: timeout,
|
|
993 interval: timeout
|
|
994 });
|
|
995 };
|
|
996
|
|
997 clock.clearInterval = function clearInterval(timerId) {
|
|
998 clock.clearTimeout(timerId);
|
|
999 };
|
|
1000
|
|
1001 clock.setImmediate = function setImmediate(func) {
|
|
1002 return addTimer(clock, {
|
|
1003 func: func,
|
|
1004 args: Array.prototype.slice.call(arguments, 1),
|
|
1005 immediate: true
|
|
1006 });
|
|
1007 };
|
|
1008
|
|
1009 clock.clearImmediate = function clearImmediate(timerId) {
|
|
1010 clock.clearTimeout(timerId);
|
|
1011 };
|
|
1012
|
|
1013 clock.tick = function tick(ms) {
|
|
1014 ms = typeof ms == "number" ? ms : parseTime(ms);
|
|
1015 var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
|
|
1016 var timer = firstTimerInRange(clock, tickFrom, tickTo);
|
|
1017
|
|
1018 var firstException;
|
|
1019 while (timer && tickFrom <= tickTo) {
|
|
1020 if (clock.timers[timer.id]) {
|
|
1021 tickFrom = clock.now = timer.callAt;
|
|
1022 try {
|
|
1023 callTimer(clock, timer);
|
|
1024 } catch (e) {
|
|
1025 firstException = firstException || e;
|
|
1026 }
|
|
1027 }
|
|
1028
|
|
1029 timer = firstTimerInRange(clock, previous, tickTo);
|
|
1030 previous = tickFrom;
|
|
1031 }
|
|
1032
|
|
1033 clock.now = tickTo;
|
|
1034
|
|
1035 if (firstException) {
|
|
1036 throw firstException;
|
|
1037 }
|
|
1038
|
|
1039 return clock.now;
|
|
1040 };
|
|
1041
|
|
1042 clock.reset = function reset() {
|
|
1043 clock.timers = {};
|
|
1044 };
|
|
1045
|
|
1046 return clock;
|
|
1047 };
|
|
1048
|
|
1049 exports.install = function install(target, now, toFake) {
|
|
1050 if (typeof target === "number") {
|
|
1051 toFake = now;
|
|
1052 now = target;
|
|
1053 target = null;
|
|
1054 }
|
|
1055
|
|
1056 if (!target) {
|
|
1057 target = global;
|
|
1058 }
|
|
1059
|
|
1060 var clock = createClock(now);
|
|
1061
|
|
1062 clock.uninstall = function () {
|
|
1063 uninstall(clock, target);
|
|
1064 };
|
|
1065
|
|
1066 clock.methods = toFake || [];
|
|
1067
|
|
1068 if (clock.methods.length === 0) {
|
|
1069 clock.methods = keys(timers);
|
|
1070 }
|
|
1071
|
|
1072 for (var i = 0, l = clock.methods.length; i < l; i++) {
|
|
1073 hijackMethod(target, clock.methods[i], clock);
|
|
1074 }
|
|
1075
|
|
1076 return clock;
|
|
1077 };
|
|
1078
|
|
1079 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
1080 },{}]},{},[1])(1)
|
|
1081 });
|
|
1082 })();
|
|
1083 var define;
|
|
1084 /**
|
|
1085 * Sinon core utilities. For internal use only.
|
|
1086 *
|
|
1087 * @author Christian Johansen ([email protected])
|
|
1088 * @license BSD
|
|
1089 *
|
|
1090 * Copyright (c) 2010-2013 Christian Johansen
|
|
1091 */
|
|
1092
|
|
1093 var sinon = (function () {
|
|
1094 "use strict";
|
|
1095
|
|
1096 var sinon;
|
|
1097 var isNode = typeof module !== "undefined" && module.exports && typeof require === "function";
|
|
1098 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1099
|
|
1100 function loadDependencies(require, exports, module) {
|
|
1101 sinon = module.exports = require("./sinon/util/core");
|
|
1102 require("./sinon/extend");
|
|
1103 require("./sinon/typeOf");
|
|
1104 require("./sinon/times_in_words");
|
|
1105 require("./sinon/spy");
|
|
1106 require("./sinon/call");
|
|
1107 require("./sinon/behavior");
|
|
1108 require("./sinon/stub");
|
|
1109 require("./sinon/mock");
|
|
1110 require("./sinon/collection");
|
|
1111 require("./sinon/assert");
|
|
1112 require("./sinon/sandbox");
|
|
1113 require("./sinon/test");
|
|
1114 require("./sinon/test_case");
|
|
1115 require("./sinon/match");
|
|
1116 require("./sinon/format");
|
|
1117 require("./sinon/log_error");
|
|
1118 }
|
|
1119
|
|
1120 if (isAMD) {
|
|
1121 define(loadDependencies);
|
|
1122 } else if (isNode) {
|
|
1123 loadDependencies(require, module.exports, module);
|
|
1124 sinon = module.exports;
|
|
1125 } else {
|
|
1126 sinon = {};
|
|
1127 }
|
|
1128
|
|
1129 return sinon;
|
|
1130 }());
|
|
1131
|
|
1132 /**
|
|
1133 * @depend ../../sinon.js
|
|
1134 */
|
|
1135 /**
|
|
1136 * Sinon core utilities. For internal use only.
|
|
1137 *
|
|
1138 * @author Christian Johansen ([email protected])
|
|
1139 * @license BSD
|
|
1140 *
|
|
1141 * Copyright (c) 2010-2013 Christian Johansen
|
|
1142 */
|
|
1143
|
|
1144 (function (sinon) {
|
|
1145 var div = typeof document != "undefined" && document.createElement("div");
|
|
1146 var hasOwn = Object.prototype.hasOwnProperty;
|
|
1147
|
|
1148 function isDOMNode(obj) {
|
|
1149 var success = false;
|
|
1150
|
|
1151 try {
|
|
1152 obj.appendChild(div);
|
|
1153 success = div.parentNode == obj;
|
|
1154 } catch (e) {
|
|
1155 return false;
|
|
1156 } finally {
|
|
1157 try {
|
|
1158 obj.removeChild(div);
|
|
1159 } catch (e) {
|
|
1160 // Remove failed, not much we can do about that
|
|
1161 }
|
|
1162 }
|
|
1163
|
|
1164 return success;
|
|
1165 }
|
|
1166
|
|
1167 function isElement(obj) {
|
|
1168 return div && obj && obj.nodeType === 1 && isDOMNode(obj);
|
|
1169 }
|
|
1170
|
|
1171 function isFunction(obj) {
|
|
1172 return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
|
|
1173 }
|
|
1174
|
|
1175 function isReallyNaN(val) {
|
|
1176 return typeof val === "number" && isNaN(val);
|
|
1177 }
|
|
1178
|
|
1179 function mirrorProperties(target, source) {
|
|
1180 for (var prop in source) {
|
|
1181 if (!hasOwn.call(target, prop)) {
|
|
1182 target[prop] = source[prop];
|
|
1183 }
|
|
1184 }
|
|
1185 }
|
|
1186
|
|
1187 function isRestorable(obj) {
|
|
1188 return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
|
|
1189 }
|
|
1190
|
|
1191 function makeApi(sinon) {
|
|
1192 sinon.wrapMethod = function wrapMethod(object, property, method) {
|
|
1193 if (!object) {
|
|
1194 throw new TypeError("Should wrap property of object");
|
|
1195 }
|
|
1196
|
|
1197 if (typeof method != "function") {
|
|
1198 throw new TypeError("Method wrapper should be function");
|
|
1199 }
|
|
1200
|
|
1201 var wrappedMethod = object[property],
|
|
1202 error;
|
|
1203
|
|
1204 if (!isFunction(wrappedMethod)) {
|
|
1205 error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
|
|
1206 property + " as function");
|
|
1207 } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
|
|
1208 error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
|
|
1209 } else if (wrappedMethod.calledBefore) {
|
|
1210 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
|
|
1211 error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
|
|
1212 }
|
|
1213
|
|
1214 if (error) {
|
|
1215 if (wrappedMethod && wrappedMethod.stackTrace) {
|
|
1216 error.stack += "\n--------------\n" + wrappedMethod.stackTrace;
|
|
1217 }
|
|
1218 throw error;
|
|
1219 }
|
|
1220
|
|
1221 // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
|
|
1222 // when using hasOwn.call on objects from other frames.
|
|
1223 var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
|
|
1224 object[property] = method;
|
|
1225 method.displayName = property;
|
|
1226 // Set up a stack trace which can be used later to find what line of
|
|
1227 // code the original method was created on.
|
|
1228 method.stackTrace = (new Error("Stack Trace for original")).stack;
|
|
1229
|
|
1230 method.restore = function () {
|
|
1231 // For prototype properties try to reset by delete first.
|
|
1232 // If this fails (ex: localStorage on mobile safari) then force a reset
|
|
1233 // via direct assignment.
|
|
1234 if (!owned) {
|
|
1235 delete object[property];
|
|
1236 }
|
|
1237 if (object[property] === method) {
|
|
1238 object[property] = wrappedMethod;
|
|
1239 }
|
|
1240 };
|
|
1241
|
|
1242 method.restore.sinon = true;
|
|
1243 mirrorProperties(method, wrappedMethod);
|
|
1244
|
|
1245 return method;
|
|
1246 };
|
|
1247
|
|
1248 sinon.create = function create(proto) {
|
|
1249 var F = function () {};
|
|
1250 F.prototype = proto;
|
|
1251 return new F();
|
|
1252 };
|
|
1253
|
|
1254 sinon.deepEqual = function deepEqual(a, b) {
|
|
1255 if (sinon.match && sinon.match.isMatcher(a)) {
|
|
1256 return a.test(b);
|
|
1257 }
|
|
1258
|
|
1259 if (typeof a != "object" || typeof b != "object") {
|
|
1260 if (isReallyNaN(a) && isReallyNaN(b)) {
|
|
1261 return true;
|
|
1262 } else {
|
|
1263 return a === b;
|
|
1264 }
|
|
1265 }
|
|
1266
|
|
1267 if (isElement(a) || isElement(b)) {
|
|
1268 return a === b;
|
|
1269 }
|
|
1270
|
|
1271 if (a === b) {
|
|
1272 return true;
|
|
1273 }
|
|
1274
|
|
1275 if ((a === null && b !== null) || (a !== null && b === null)) {
|
|
1276 return false;
|
|
1277 }
|
|
1278
|
|
1279 if (a instanceof RegExp && b instanceof RegExp) {
|
|
1280 return (a.source === b.source) && (a.global === b.global) &&
|
|
1281 (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
|
|
1282 }
|
|
1283
|
|
1284 var aString = Object.prototype.toString.call(a);
|
|
1285 if (aString != Object.prototype.toString.call(b)) {
|
|
1286 return false;
|
|
1287 }
|
|
1288
|
|
1289 if (aString == "[object Date]") {
|
|
1290 return a.valueOf() === b.valueOf();
|
|
1291 }
|
|
1292
|
|
1293 var prop, aLength = 0, bLength = 0;
|
|
1294
|
|
1295 if (aString == "[object Array]" && a.length !== b.length) {
|
|
1296 return false;
|
|
1297 }
|
|
1298
|
|
1299 for (prop in a) {
|
|
1300 aLength += 1;
|
|
1301
|
|
1302 if (!(prop in b)) {
|
|
1303 return false;
|
|
1304 }
|
|
1305
|
|
1306 if (!deepEqual(a[prop], b[prop])) {
|
|
1307 return false;
|
|
1308 }
|
|
1309 }
|
|
1310
|
|
1311 for (prop in b) {
|
|
1312 bLength += 1;
|
|
1313 }
|
|
1314
|
|
1315 return aLength == bLength;
|
|
1316 };
|
|
1317
|
|
1318 sinon.functionName = function functionName(func) {
|
|
1319 var name = func.displayName || func.name;
|
|
1320
|
|
1321 // Use function decomposition as a last resort to get function
|
|
1322 // name. Does not rely on function decomposition to work - if it
|
|
1323 // doesn't debugging will be slightly less informative
|
|
1324 // (i.e. toString will say 'spy' rather than 'myFunc').
|
|
1325 if (!name) {
|
|
1326 var matches = func.toString().match(/function ([^\s\(]+)/);
|
|
1327 name = matches && matches[1];
|
|
1328 }
|
|
1329
|
|
1330 return name;
|
|
1331 };
|
|
1332
|
|
1333 sinon.functionToString = function toString() {
|
|
1334 if (this.getCall && this.callCount) {
|
|
1335 var thisValue, prop, i = this.callCount;
|
|
1336
|
|
1337 while (i--) {
|
|
1338 thisValue = this.getCall(i).thisValue;
|
|
1339
|
|
1340 for (prop in thisValue) {
|
|
1341 if (thisValue[prop] === this) {
|
|
1342 return prop;
|
|
1343 }
|
|
1344 }
|
|
1345 }
|
|
1346 }
|
|
1347
|
|
1348 return this.displayName || "sinon fake";
|
|
1349 };
|
|
1350
|
|
1351 sinon.getConfig = function (custom) {
|
|
1352 var config = {};
|
|
1353 custom = custom || {};
|
|
1354 var defaults = sinon.defaultConfig;
|
|
1355
|
|
1356 for (var prop in defaults) {
|
|
1357 if (defaults.hasOwnProperty(prop)) {
|
|
1358 config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
|
|
1359 }
|
|
1360 }
|
|
1361
|
|
1362 return config;
|
|
1363 };
|
|
1364
|
|
1365 sinon.defaultConfig = {
|
|
1366 injectIntoThis: true,
|
|
1367 injectInto: null,
|
|
1368 properties: ["spy", "stub", "mock", "clock", "server", "requests"],
|
|
1369 useFakeTimers: true,
|
|
1370 useFakeServer: true
|
|
1371 };
|
|
1372
|
|
1373 sinon.timesInWords = function timesInWords(count) {
|
|
1374 return count == 1 && "once" ||
|
|
1375 count == 2 && "twice" ||
|
|
1376 count == 3 && "thrice" ||
|
|
1377 (count || 0) + " times";
|
|
1378 };
|
|
1379
|
|
1380 sinon.calledInOrder = function (spies) {
|
|
1381 for (var i = 1, l = spies.length; i < l; i++) {
|
|
1382 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
|
|
1383 return false;
|
|
1384 }
|
|
1385 }
|
|
1386
|
|
1387 return true;
|
|
1388 };
|
|
1389
|
|
1390 sinon.orderByFirstCall = function (spies) {
|
|
1391 return spies.sort(function (a, b) {
|
|
1392 // uuid, won't ever be equal
|
|
1393 var aCall = a.getCall(0);
|
|
1394 var bCall = b.getCall(0);
|
|
1395 var aId = aCall && aCall.callId || -1;
|
|
1396 var bId = bCall && bCall.callId || -1;
|
|
1397
|
|
1398 return aId < bId ? -1 : 1;
|
|
1399 });
|
|
1400 };
|
|
1401
|
|
1402 sinon.createStubInstance = function (constructor) {
|
|
1403 if (typeof constructor !== "function") {
|
|
1404 throw new TypeError("The constructor should be a function.");
|
|
1405 }
|
|
1406 return sinon.stub(sinon.create(constructor.prototype));
|
|
1407 };
|
|
1408
|
|
1409 sinon.restore = function (object) {
|
|
1410 if (object !== null && typeof object === "object") {
|
|
1411 for (var prop in object) {
|
|
1412 if (isRestorable(object[prop])) {
|
|
1413 object[prop].restore();
|
|
1414 }
|
|
1415 }
|
|
1416 } else if (isRestorable(object)) {
|
|
1417 object.restore();
|
|
1418 }
|
|
1419 };
|
|
1420
|
|
1421 return sinon;
|
|
1422 }
|
|
1423
|
|
1424 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1425 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1426
|
|
1427 function loadDependencies(require, exports) {
|
|
1428 makeApi(exports);
|
|
1429 }
|
|
1430
|
|
1431 if (isAMD) {
|
|
1432 define(loadDependencies);
|
|
1433 } else if (isNode) {
|
|
1434 loadDependencies(require, module.exports);
|
|
1435 } else if (!sinon) {
|
|
1436 return;
|
|
1437 } else {
|
|
1438 makeApi(sinon);
|
|
1439 }
|
|
1440 }(typeof sinon == "object" && sinon || null));
|
|
1441
|
|
1442 /**
|
|
1443 * @depend ../sinon.js
|
|
1444 */
|
|
1445
|
|
1446 (function (sinon) {
|
|
1447 function makeApi(sinon) {
|
|
1448
|
|
1449 // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
|
|
1450 var hasDontEnumBug = (function () {
|
|
1451 var obj = {
|
|
1452 constructor: function () {
|
|
1453 return "0";
|
|
1454 },
|
|
1455 toString: function () {
|
|
1456 return "1";
|
|
1457 },
|
|
1458 valueOf: function () {
|
|
1459 return "2";
|
|
1460 },
|
|
1461 toLocaleString: function () {
|
|
1462 return "3";
|
|
1463 },
|
|
1464 prototype: function () {
|
|
1465 return "4";
|
|
1466 },
|
|
1467 isPrototypeOf: function () {
|
|
1468 return "5";
|
|
1469 },
|
|
1470 propertyIsEnumerable: function () {
|
|
1471 return "6";
|
|
1472 },
|
|
1473 hasOwnProperty: function () {
|
|
1474 return "7";
|
|
1475 },
|
|
1476 length: function () {
|
|
1477 return "8";
|
|
1478 },
|
|
1479 unique: function () {
|
|
1480 return "9"
|
|
1481 }
|
|
1482 };
|
|
1483
|
|
1484 var result = [];
|
|
1485 for (var prop in obj) {
|
|
1486 result.push(obj[prop]());
|
|
1487 }
|
|
1488 return result.join("") !== "0123456789";
|
|
1489 })();
|
|
1490
|
|
1491 /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will
|
|
1492 * override properties in previous sources.
|
|
1493 *
|
|
1494 * target - The Object to extend
|
|
1495 * sources - Objects to copy properties from.
|
|
1496 *
|
|
1497 * Returns the extended target
|
|
1498 */
|
|
1499 function extend(target /*, sources */) {
|
|
1500 var sources = Array.prototype.slice.call(arguments, 1),
|
|
1501 source, i, prop;
|
|
1502
|
|
1503 for (i = 0; i < sources.length; i++) {
|
|
1504 source = sources[i];
|
|
1505
|
|
1506 for (prop in source) {
|
|
1507 if (source.hasOwnProperty(prop)) {
|
|
1508 target[prop] = source[prop];
|
|
1509 }
|
|
1510 }
|
|
1511
|
|
1512 // Make sure we copy (own) toString method even when in JScript with DontEnum bug
|
|
1513 // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
|
|
1514 if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) {
|
|
1515 target.toString = source.toString;
|
|
1516 }
|
|
1517 }
|
|
1518
|
|
1519 return target;
|
|
1520 };
|
|
1521
|
|
1522 sinon.extend = extend;
|
|
1523 return sinon.extend;
|
|
1524 }
|
|
1525
|
|
1526 function loadDependencies(require, exports, module) {
|
|
1527 var sinon = require("./util/core");
|
|
1528 module.exports = makeApi(sinon);
|
|
1529 }
|
|
1530
|
|
1531 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1532 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1533
|
|
1534 if (isAMD) {
|
|
1535 define(loadDependencies);
|
|
1536 } else if (isNode) {
|
|
1537 loadDependencies(require, module.exports, module);
|
|
1538 } else if (!sinon) {
|
|
1539 return;
|
|
1540 } else {
|
|
1541 makeApi(sinon);
|
|
1542 }
|
|
1543 }(typeof sinon == "object" && sinon || null));
|
|
1544
|
|
1545 /**
|
|
1546 * @depend ../sinon.js
|
|
1547 */
|
|
1548
|
|
1549 (function (sinon) {
|
|
1550 function makeApi(sinon) {
|
|
1551
|
|
1552 function timesInWords(count) {
|
|
1553 switch (count) {
|
|
1554 case 1:
|
|
1555 return "once";
|
|
1556 case 2:
|
|
1557 return "twice";
|
|
1558 case 3:
|
|
1559 return "thrice";
|
|
1560 default:
|
|
1561 return (count || 0) + " times";
|
|
1562 }
|
|
1563 }
|
|
1564
|
|
1565 sinon.timesInWords = timesInWords;
|
|
1566 return sinon.timesInWords;
|
|
1567 }
|
|
1568
|
|
1569 function loadDependencies(require, exports, module) {
|
|
1570 var sinon = require("./util/core");
|
|
1571 module.exports = makeApi(sinon);
|
|
1572 }
|
|
1573
|
|
1574 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1575 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1576
|
|
1577 if (isAMD) {
|
|
1578 define(loadDependencies);
|
|
1579 } else if (isNode) {
|
|
1580 loadDependencies(require, module.exports, module);
|
|
1581 } else if (!sinon) {
|
|
1582 return;
|
|
1583 } else {
|
|
1584 makeApi(sinon);
|
|
1585 }
|
|
1586 }(typeof sinon == "object" && sinon || null));
|
|
1587
|
|
1588 /**
|
|
1589 * @depend ../sinon.js
|
|
1590 */
|
|
1591 /**
|
|
1592 * Format functions
|
|
1593 *
|
|
1594 * @author Christian Johansen ([email protected])
|
|
1595 * @license BSD
|
|
1596 *
|
|
1597 * Copyright (c) 2010-2014 Christian Johansen
|
|
1598 */
|
|
1599
|
|
1600 (function (sinon, formatio) {
|
|
1601 function makeApi(sinon) {
|
|
1602 function typeOf(value) {
|
|
1603 if (value === null) {
|
|
1604 return "null";
|
|
1605 } else if (value === undefined) {
|
|
1606 return "undefined";
|
|
1607 }
|
|
1608 var string = Object.prototype.toString.call(value);
|
|
1609 return string.substring(8, string.length - 1).toLowerCase();
|
|
1610 };
|
|
1611
|
|
1612 sinon.typeOf = typeOf;
|
|
1613 return sinon.typeOf;
|
|
1614 }
|
|
1615
|
|
1616 function loadDependencies(require, exports, module) {
|
|
1617 var sinon = require("./util/core");
|
|
1618 module.exports = makeApi(sinon);
|
|
1619 }
|
|
1620
|
|
1621 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1622 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1623
|
|
1624 if (isAMD) {
|
|
1625 define(loadDependencies);
|
|
1626 } else if (isNode) {
|
|
1627 loadDependencies(require, module.exports, module);
|
|
1628 } else if (!sinon) {
|
|
1629 return;
|
|
1630 } else {
|
|
1631 makeApi(sinon);
|
|
1632 }
|
|
1633 }(
|
|
1634 (typeof sinon == "object" && sinon || null),
|
|
1635 (typeof formatio == "object" && formatio)
|
|
1636 ));
|
|
1637
|
|
1638 /**
|
|
1639 * @depend util/core.js
|
|
1640 * @depend typeOf.js
|
|
1641 */
|
|
1642 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
|
|
1643 /*global module, require, sinon*/
|
|
1644 /**
|
|
1645 * Match functions
|
|
1646 *
|
|
1647 * @author Maximilian Antoni ([email protected])
|
|
1648 * @license BSD
|
|
1649 *
|
|
1650 * Copyright (c) 2012 Maximilian Antoni
|
|
1651 */
|
|
1652
|
|
1653 (function (sinon) {
|
|
1654 function makeApi(sinon) {
|
|
1655 function assertType(value, type, name) {
|
|
1656 var actual = sinon.typeOf(value);
|
|
1657 if (actual !== type) {
|
|
1658 throw new TypeError("Expected type of " + name + " to be " +
|
|
1659 type + ", but was " + actual);
|
|
1660 }
|
|
1661 }
|
|
1662
|
|
1663 var matcher = {
|
|
1664 toString: function () {
|
|
1665 return this.message;
|
|
1666 }
|
|
1667 };
|
|
1668
|
|
1669 function isMatcher(object) {
|
|
1670 return matcher.isPrototypeOf(object);
|
|
1671 }
|
|
1672
|
|
1673 function matchObject(expectation, actual) {
|
|
1674 if (actual === null || actual === undefined) {
|
|
1675 return false;
|
|
1676 }
|
|
1677 for (var key in expectation) {
|
|
1678 if (expectation.hasOwnProperty(key)) {
|
|
1679 var exp = expectation[key];
|
|
1680 var act = actual[key];
|
|
1681 if (match.isMatcher(exp)) {
|
|
1682 if (!exp.test(act)) {
|
|
1683 return false;
|
|
1684 }
|
|
1685 } else if (sinon.typeOf(exp) === "object") {
|
|
1686 if (!matchObject(exp, act)) {
|
|
1687 return false;
|
|
1688 }
|
|
1689 } else if (!sinon.deepEqual(exp, act)) {
|
|
1690 return false;
|
|
1691 }
|
|
1692 }
|
|
1693 }
|
|
1694 return true;
|
|
1695 }
|
|
1696
|
|
1697 matcher.or = function (m2) {
|
|
1698 if (!arguments.length) {
|
|
1699 throw new TypeError("Matcher expected");
|
|
1700 } else if (!isMatcher(m2)) {
|
|
1701 m2 = match(m2);
|
|
1702 }
|
|
1703 var m1 = this;
|
|
1704 var or = sinon.create(matcher);
|
|
1705 or.test = function (actual) {
|
|
1706 return m1.test(actual) || m2.test(actual);
|
|
1707 };
|
|
1708 or.message = m1.message + ".or(" + m2.message + ")";
|
|
1709 return or;
|
|
1710 };
|
|
1711
|
|
1712 matcher.and = function (m2) {
|
|
1713 if (!arguments.length) {
|
|
1714 throw new TypeError("Matcher expected");
|
|
1715 } else if (!isMatcher(m2)) {
|
|
1716 m2 = match(m2);
|
|
1717 }
|
|
1718 var m1 = this;
|
|
1719 var and = sinon.create(matcher);
|
|
1720 and.test = function (actual) {
|
|
1721 return m1.test(actual) && m2.test(actual);
|
|
1722 };
|
|
1723 and.message = m1.message + ".and(" + m2.message + ")";
|
|
1724 return and;
|
|
1725 };
|
|
1726
|
|
1727 var match = function (expectation, message) {
|
|
1728 var m = sinon.create(matcher);
|
|
1729 var type = sinon.typeOf(expectation);
|
|
1730 switch (type) {
|
|
1731 case "object":
|
|
1732 if (typeof expectation.test === "function") {
|
|
1733 m.test = function (actual) {
|
|
1734 return expectation.test(actual) === true;
|
|
1735 };
|
|
1736 m.message = "match(" + sinon.functionName(expectation.test) + ")";
|
|
1737 return m;
|
|
1738 }
|
|
1739 var str = [];
|
|
1740 for (var key in expectation) {
|
|
1741 if (expectation.hasOwnProperty(key)) {
|
|
1742 str.push(key + ": " + expectation[key]);
|
|
1743 }
|
|
1744 }
|
|
1745 m.test = function (actual) {
|
|
1746 return matchObject(expectation, actual);
|
|
1747 };
|
|
1748 m.message = "match(" + str.join(", ") + ")";
|
|
1749 break;
|
|
1750 case "number":
|
|
1751 m.test = function (actual) {
|
|
1752 return expectation == actual;
|
|
1753 };
|
|
1754 break;
|
|
1755 case "string":
|
|
1756 m.test = function (actual) {
|
|
1757 if (typeof actual !== "string") {
|
|
1758 return false;
|
|
1759 }
|
|
1760 return actual.indexOf(expectation) !== -1;
|
|
1761 };
|
|
1762 m.message = "match(\"" + expectation + "\")";
|
|
1763 break;
|
|
1764 case "regexp":
|
|
1765 m.test = function (actual) {
|
|
1766 if (typeof actual !== "string") {
|
|
1767 return false;
|
|
1768 }
|
|
1769 return expectation.test(actual);
|
|
1770 };
|
|
1771 break;
|
|
1772 case "function":
|
|
1773 m.test = expectation;
|
|
1774 if (message) {
|
|
1775 m.message = message;
|
|
1776 } else {
|
|
1777 m.message = "match(" + sinon.functionName(expectation) + ")";
|
|
1778 }
|
|
1779 break;
|
|
1780 default:
|
|
1781 m.test = function (actual) {
|
|
1782 return sinon.deepEqual(expectation, actual);
|
|
1783 };
|
|
1784 }
|
|
1785 if (!m.message) {
|
|
1786 m.message = "match(" + expectation + ")";
|
|
1787 }
|
|
1788 return m;
|
|
1789 };
|
|
1790
|
|
1791 match.isMatcher = isMatcher;
|
|
1792
|
|
1793 match.any = match(function () {
|
|
1794 return true;
|
|
1795 }, "any");
|
|
1796
|
|
1797 match.defined = match(function (actual) {
|
|
1798 return actual !== null && actual !== undefined;
|
|
1799 }, "defined");
|
|
1800
|
|
1801 match.truthy = match(function (actual) {
|
|
1802 return !!actual;
|
|
1803 }, "truthy");
|
|
1804
|
|
1805 match.falsy = match(function (actual) {
|
|
1806 return !actual;
|
|
1807 }, "falsy");
|
|
1808
|
|
1809 match.same = function (expectation) {
|
|
1810 return match(function (actual) {
|
|
1811 return expectation === actual;
|
|
1812 }, "same(" + expectation + ")");
|
|
1813 };
|
|
1814
|
|
1815 match.typeOf = function (type) {
|
|
1816 assertType(type, "string", "type");
|
|
1817 return match(function (actual) {
|
|
1818 return sinon.typeOf(actual) === type;
|
|
1819 }, "typeOf(\"" + type + "\")");
|
|
1820 };
|
|
1821
|
|
1822 match.instanceOf = function (type) {
|
|
1823 assertType(type, "function", "type");
|
|
1824 return match(function (actual) {
|
|
1825 return actual instanceof type;
|
|
1826 }, "instanceOf(" + sinon.functionName(type) + ")");
|
|
1827 };
|
|
1828
|
|
1829 function createPropertyMatcher(propertyTest, messagePrefix) {
|
|
1830 return function (property, value) {
|
|
1831 assertType(property, "string", "property");
|
|
1832 var onlyProperty = arguments.length === 1;
|
|
1833 var message = messagePrefix + "(\"" + property + "\"";
|
|
1834 if (!onlyProperty) {
|
|
1835 message += ", " + value;
|
|
1836 }
|
|
1837 message += ")";
|
|
1838 return match(function (actual) {
|
|
1839 if (actual === undefined || actual === null ||
|
|
1840 !propertyTest(actual, property)) {
|
|
1841 return false;
|
|
1842 }
|
|
1843 return onlyProperty || sinon.deepEqual(value, actual[property]);
|
|
1844 }, message);
|
|
1845 };
|
|
1846 }
|
|
1847
|
|
1848 match.has = createPropertyMatcher(function (actual, property) {
|
|
1849 if (typeof actual === "object") {
|
|
1850 return property in actual;
|
|
1851 }
|
|
1852 return actual[property] !== undefined;
|
|
1853 }, "has");
|
|
1854
|
|
1855 match.hasOwn = createPropertyMatcher(function (actual, property) {
|
|
1856 return actual.hasOwnProperty(property);
|
|
1857 }, "hasOwn");
|
|
1858
|
|
1859 match.bool = match.typeOf("boolean");
|
|
1860 match.number = match.typeOf("number");
|
|
1861 match.string = match.typeOf("string");
|
|
1862 match.object = match.typeOf("object");
|
|
1863 match.func = match.typeOf("function");
|
|
1864 match.array = match.typeOf("array");
|
|
1865 match.regexp = match.typeOf("regexp");
|
|
1866 match.date = match.typeOf("date");
|
|
1867
|
|
1868 sinon.match = match;
|
|
1869 return match;
|
|
1870 }
|
|
1871
|
|
1872 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1873 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1874
|
|
1875 function loadDependencies(require, exports, module) {
|
|
1876 var sinon = require("./util/core");
|
|
1877 module.exports = makeApi(sinon);
|
|
1878 }
|
|
1879
|
|
1880 if (isAMD) {
|
|
1881 define(loadDependencies);
|
|
1882 } else if (isNode) {
|
|
1883 loadDependencies(require, module.exports, module);
|
|
1884 } else if (!sinon) {
|
|
1885 return;
|
|
1886 } else {
|
|
1887 makeApi(sinon);
|
|
1888 }
|
|
1889 }(typeof sinon == "object" && sinon || null));
|
|
1890
|
|
1891 /**
|
|
1892 * @depend ../sinon.js
|
|
1893 */
|
|
1894 /**
|
|
1895 * Format functions
|
|
1896 *
|
|
1897 * @author Christian Johansen ([email protected])
|
|
1898 * @license BSD
|
|
1899 *
|
|
1900 * Copyright (c) 2010-2014 Christian Johansen
|
|
1901 */
|
|
1902
|
|
1903 (function (sinon, formatio) {
|
|
1904 function makeApi(sinon) {
|
|
1905 function valueFormatter(value) {
|
|
1906 return "" + value;
|
|
1907 }
|
|
1908
|
|
1909 function getFormatioFormatter() {
|
|
1910 var formatter = formatio.configure({
|
|
1911 quoteStrings: false,
|
|
1912 limitChildrenCount: 250
|
|
1913 });
|
|
1914
|
|
1915 function format() {
|
|
1916 return formatter.ascii.apply(formatter, arguments);
|
|
1917 };
|
|
1918
|
|
1919 return format;
|
|
1920 }
|
|
1921
|
|
1922 function getNodeFormatter(value) {
|
|
1923 function format(value) {
|
|
1924 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
|
|
1925 };
|
|
1926
|
|
1927 try {
|
|
1928 var util = require("util");
|
|
1929 } catch (e) {
|
|
1930 /* Node, but no util module - would be very old, but better safe than sorry */
|
|
1931 }
|
|
1932
|
|
1933 return util ? format : valueFormatter;
|
|
1934 }
|
|
1935
|
|
1936 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function",
|
|
1937 formatter;
|
|
1938
|
|
1939 if (isNode) {
|
|
1940 try {
|
|
1941 formatio = require("formatio");
|
|
1942 } catch (e) {}
|
|
1943 }
|
|
1944
|
|
1945 if (formatio) {
|
|
1946 formatter = getFormatioFormatter()
|
|
1947 } else if (isNode) {
|
|
1948 formatter = getNodeFormatter();
|
|
1949 } else {
|
|
1950 formatter = valueFormatter;
|
|
1951 }
|
|
1952
|
|
1953 sinon.format = formatter;
|
|
1954 return sinon.format;
|
|
1955 }
|
|
1956
|
|
1957 function loadDependencies(require, exports, module) {
|
|
1958 var sinon = require("./util/core");
|
|
1959 module.exports = makeApi(sinon);
|
|
1960 }
|
|
1961
|
|
1962 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
1963 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
1964
|
|
1965 if (isAMD) {
|
|
1966 define(loadDependencies);
|
|
1967 } else if (isNode) {
|
|
1968 loadDependencies(require, module.exports, module);
|
|
1969 } else if (!sinon) {
|
|
1970 return;
|
|
1971 } else {
|
|
1972 makeApi(sinon);
|
|
1973 }
|
|
1974 }(
|
|
1975 (typeof sinon == "object" && sinon || null),
|
|
1976 (typeof formatio == "object" && formatio)
|
|
1977 ));
|
|
1978
|
|
1979 /**
|
|
1980 * @depend util/core.js
|
|
1981 * @depend match.js
|
|
1982 * @depend format.js
|
|
1983 */
|
|
1984 /**
|
|
1985 * Spy calls
|
|
1986 *
|
|
1987 * @author Christian Johansen ([email protected])
|
|
1988 * @author Maximilian Antoni ([email protected])
|
|
1989 * @license BSD
|
|
1990 *
|
|
1991 * Copyright (c) 2010-2013 Christian Johansen
|
|
1992 * Copyright (c) 2013 Maximilian Antoni
|
|
1993 */
|
|
1994
|
|
1995 (function (sinon) {
|
|
1996 function makeApi(sinon) {
|
|
1997 function throwYieldError(proxy, text, args) {
|
|
1998 var msg = sinon.functionName(proxy) + text;
|
|
1999 if (args.length) {
|
|
2000 msg += " Received [" + slice.call(args).join(", ") + "]";
|
|
2001 }
|
|
2002 throw new Error(msg);
|
|
2003 }
|
|
2004
|
|
2005 var slice = Array.prototype.slice;
|
|
2006
|
|
2007 var callProto = {
|
|
2008 calledOn: function calledOn(thisValue) {
|
|
2009 if (sinon.match && sinon.match.isMatcher(thisValue)) {
|
|
2010 return thisValue.test(this.thisValue);
|
|
2011 }
|
|
2012 return this.thisValue === thisValue;
|
|
2013 },
|
|
2014
|
|
2015 calledWith: function calledWith() {
|
|
2016 for (var i = 0, l = arguments.length; i < l; i += 1) {
|
|
2017 if (!sinon.deepEqual(arguments[i], this.args[i])) {
|
|
2018 return false;
|
|
2019 }
|
|
2020 }
|
|
2021
|
|
2022 return true;
|
|
2023 },
|
|
2024
|
|
2025 calledWithMatch: function calledWithMatch() {
|
|
2026 for (var i = 0, l = arguments.length; i < l; i += 1) {
|
|
2027 var actual = this.args[i];
|
|
2028 var expectation = arguments[i];
|
|
2029 if (!sinon.match || !sinon.match(expectation).test(actual)) {
|
|
2030 return false;
|
|
2031 }
|
|
2032 }
|
|
2033 return true;
|
|
2034 },
|
|
2035
|
|
2036 calledWithExactly: function calledWithExactly() {
|
|
2037 return arguments.length == this.args.length &&
|
|
2038 this.calledWith.apply(this, arguments);
|
|
2039 },
|
|
2040
|
|
2041 notCalledWith: function notCalledWith() {
|
|
2042 return !this.calledWith.apply(this, arguments);
|
|
2043 },
|
|
2044
|
|
2045 notCalledWithMatch: function notCalledWithMatch() {
|
|
2046 return !this.calledWithMatch.apply(this, arguments);
|
|
2047 },
|
|
2048
|
|
2049 returned: function returned(value) {
|
|
2050 return sinon.deepEqual(value, this.returnValue);
|
|
2051 },
|
|
2052
|
|
2053 threw: function threw(error) {
|
|
2054 if (typeof error === "undefined" || !this.exception) {
|
|
2055 return !!this.exception;
|
|
2056 }
|
|
2057
|
|
2058 return this.exception === error || this.exception.name === error;
|
|
2059 },
|
|
2060
|
|
2061 calledWithNew: function calledWithNew() {
|
|
2062 return this.proxy.prototype && this.thisValue instanceof this.proxy;
|
|
2063 },
|
|
2064
|
|
2065 calledBefore: function (other) {
|
|
2066 return this.callId < other.callId;
|
|
2067 },
|
|
2068
|
|
2069 calledAfter: function (other) {
|
|
2070 return this.callId > other.callId;
|
|
2071 },
|
|
2072
|
|
2073 callArg: function (pos) {
|
|
2074 this.args[pos]();
|
|
2075 },
|
|
2076
|
|
2077 callArgOn: function (pos, thisValue) {
|
|
2078 this.args[pos].apply(thisValue);
|
|
2079 },
|
|
2080
|
|
2081 callArgWith: function (pos) {
|
|
2082 this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
|
|
2083 },
|
|
2084
|
|
2085 callArgOnWith: function (pos, thisValue) {
|
|
2086 var args = slice.call(arguments, 2);
|
|
2087 this.args[pos].apply(thisValue, args);
|
|
2088 },
|
|
2089
|
|
2090 yield: function () {
|
|
2091 this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
|
|
2092 },
|
|
2093
|
|
2094 yieldOn: function (thisValue) {
|
|
2095 var args = this.args;
|
|
2096 for (var i = 0, l = args.length; i < l; ++i) {
|
|
2097 if (typeof args[i] === "function") {
|
|
2098 args[i].apply(thisValue, slice.call(arguments, 1));
|
|
2099 return;
|
|
2100 }
|
|
2101 }
|
|
2102 throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
|
|
2103 },
|
|
2104
|
|
2105 yieldTo: function (prop) {
|
|
2106 this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
|
|
2107 },
|
|
2108
|
|
2109 yieldToOn: function (prop, thisValue) {
|
|
2110 var args = this.args;
|
|
2111 for (var i = 0, l = args.length; i < l; ++i) {
|
|
2112 if (args[i] && typeof args[i][prop] === "function") {
|
|
2113 args[i][prop].apply(thisValue, slice.call(arguments, 2));
|
|
2114 return;
|
|
2115 }
|
|
2116 }
|
|
2117 throwYieldError(this.proxy, " cannot yield to '" + prop +
|
|
2118 "' since no callback was passed.", args);
|
|
2119 },
|
|
2120
|
|
2121 toString: function () {
|
|
2122 var callStr = this.proxy.toString() + "(";
|
|
2123 var args = [];
|
|
2124
|
|
2125 for (var i = 0, l = this.args.length; i < l; ++i) {
|
|
2126 args.push(sinon.format(this.args[i]));
|
|
2127 }
|
|
2128
|
|
2129 callStr = callStr + args.join(", ") + ")";
|
|
2130
|
|
2131 if (typeof this.returnValue != "undefined") {
|
|
2132 callStr += " => " + sinon.format(this.returnValue);
|
|
2133 }
|
|
2134
|
|
2135 if (this.exception) {
|
|
2136 callStr += " !" + this.exception.name;
|
|
2137
|
|
2138 if (this.exception.message) {
|
|
2139 callStr += "(" + this.exception.message + ")";
|
|
2140 }
|
|
2141 }
|
|
2142
|
|
2143 return callStr;
|
|
2144 }
|
|
2145 };
|
|
2146
|
|
2147 callProto.invokeCallback = callProto.yield;
|
|
2148
|
|
2149 function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
|
|
2150 if (typeof id !== "number") {
|
|
2151 throw new TypeError("Call id is not a number");
|
|
2152 }
|
|
2153 var proxyCall = sinon.create(callProto);
|
|
2154 proxyCall.proxy = spy;
|
|
2155 proxyCall.thisValue = thisValue;
|
|
2156 proxyCall.args = args;
|
|
2157 proxyCall.returnValue = returnValue;
|
|
2158 proxyCall.exception = exception;
|
|
2159 proxyCall.callId = id;
|
|
2160
|
|
2161 return proxyCall;
|
|
2162 }
|
|
2163 createSpyCall.toString = callProto.toString; // used by mocks
|
|
2164
|
|
2165 sinon.spyCall = createSpyCall;
|
|
2166 return createSpyCall;
|
|
2167 }
|
|
2168
|
|
2169 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
2170 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
2171
|
|
2172 function loadDependencies(require, exports, module) {
|
|
2173 var sinon = require("./util/core");
|
|
2174 require("./match");
|
|
2175 module.exports = makeApi(sinon);
|
|
2176 }
|
|
2177
|
|
2178 if (isAMD) {
|
|
2179 define(loadDependencies);
|
|
2180 } else if (isNode) {
|
|
2181 loadDependencies(require, module.exports, module);
|
|
2182 } else if (!sinon) {
|
|
2183 return;
|
|
2184 } else {
|
|
2185 makeApi(sinon);
|
|
2186 }
|
|
2187 }(typeof sinon == "object" && sinon || null));
|
|
2188
|
|
2189 /**
|
|
2190 * @depend times_in_words.js
|
|
2191 * @depend util/core.js
|
|
2192 * @depend extend.js
|
|
2193 * @depend call.js
|
|
2194 * @depend format.js
|
|
2195 */
|
|
2196 /**
|
|
2197 * Spy functions
|
|
2198 *
|
|
2199 * @author Christian Johansen ([email protected])
|
|
2200 * @license BSD
|
|
2201 *
|
|
2202 * Copyright (c) 2010-2013 Christian Johansen
|
|
2203 */
|
|
2204
|
|
2205 (function (sinon) {
|
|
2206 function makeApi(sinon) {
|
|
2207 var push = Array.prototype.push;
|
|
2208 var slice = Array.prototype.slice;
|
|
2209 var callId = 0;
|
|
2210
|
|
2211 function spy(object, property) {
|
|
2212 if (!property && typeof object == "function") {
|
|
2213 return spy.create(object);
|
|
2214 }
|
|
2215
|
|
2216 if (!object && !property) {
|
|
2217 return spy.create(function () { });
|
|
2218 }
|
|
2219
|
|
2220 var method = object[property];
|
|
2221 return sinon.wrapMethod(object, property, spy.create(method));
|
|
2222 }
|
|
2223
|
|
2224 function matchingFake(fakes, args, strict) {
|
|
2225 if (!fakes) {
|
|
2226 return;
|
|
2227 }
|
|
2228
|
|
2229 for (var i = 0, l = fakes.length; i < l; i++) {
|
|
2230 if (fakes[i].matches(args, strict)) {
|
|
2231 return fakes[i];
|
|
2232 }
|
|
2233 }
|
|
2234 }
|
|
2235
|
|
2236 function incrementCallCount() {
|
|
2237 this.called = true;
|
|
2238 this.callCount += 1;
|
|
2239 this.notCalled = false;
|
|
2240 this.calledOnce = this.callCount == 1;
|
|
2241 this.calledTwice = this.callCount == 2;
|
|
2242 this.calledThrice = this.callCount == 3;
|
|
2243 }
|
|
2244
|
|
2245 function createCallProperties() {
|
|
2246 this.firstCall = this.getCall(0);
|
|
2247 this.secondCall = this.getCall(1);
|
|
2248 this.thirdCall = this.getCall(2);
|
|
2249 this.lastCall = this.getCall(this.callCount - 1);
|
|
2250 }
|
|
2251
|
|
2252 var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
|
|
2253 function createProxy(func) {
|
|
2254 // Retain the function length:
|
|
2255 var p;
|
|
2256 if (func.length) {
|
|
2257 eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
|
|
2258 ") { return p.invoke(func, this, slice.call(arguments)); });");
|
|
2259 } else {
|
|
2260 p = function proxy() {
|
|
2261 return p.invoke(func, this, slice.call(arguments));
|
|
2262 };
|
|
2263 }
|
|
2264 return p;
|
|
2265 }
|
|
2266
|
|
2267 var uuid = 0;
|
|
2268
|
|
2269 // Public API
|
|
2270 var spyApi = {
|
|
2271 reset: function () {
|
|
2272 if (this.invoking) {
|
|
2273 var err = new Error("Cannot reset Sinon function while invoking it. " +
|
|
2274 "Move the call to .reset outside of the callback.");
|
|
2275 err.name = "InvalidResetException";
|
|
2276 throw err;
|
|
2277 }
|
|
2278
|
|
2279 this.called = false;
|
|
2280 this.notCalled = true;
|
|
2281 this.calledOnce = false;
|
|
2282 this.calledTwice = false;
|
|
2283 this.calledThrice = false;
|
|
2284 this.callCount = 0;
|
|
2285 this.firstCall = null;
|
|
2286 this.secondCall = null;
|
|
2287 this.thirdCall = null;
|
|
2288 this.lastCall = null;
|
|
2289 this.args = [];
|
|
2290 this.returnValues = [];
|
|
2291 this.thisValues = [];
|
|
2292 this.exceptions = [];
|
|
2293 this.callIds = [];
|
|
2294 if (this.fakes) {
|
|
2295 for (var i = 0; i < this.fakes.length; i++) {
|
|
2296 this.fakes[i].reset();
|
|
2297 }
|
|
2298 }
|
|
2299 },
|
|
2300
|
|
2301 create: function create(func) {
|
|
2302 var name;
|
|
2303
|
|
2304 if (typeof func != "function") {
|
|
2305 func = function () { };
|
|
2306 } else {
|
|
2307 name = sinon.functionName(func);
|
|
2308 }
|
|
2309
|
|
2310 var proxy = createProxy(func);
|
|
2311
|
|
2312 sinon.extend(proxy, spy);
|
|
2313 delete proxy.create;
|
|
2314 sinon.extend(proxy, func);
|
|
2315
|
|
2316 proxy.reset();
|
|
2317 proxy.prototype = func.prototype;
|
|
2318 proxy.displayName = name || "spy";
|
|
2319 proxy.toString = sinon.functionToString;
|
|
2320 proxy.instantiateFake = sinon.spy.create;
|
|
2321 proxy.id = "spy#" + uuid++;
|
|
2322
|
|
2323 return proxy;
|
|
2324 },
|
|
2325
|
|
2326 invoke: function invoke(func, thisValue, args) {
|
|
2327 var matching = matchingFake(this.fakes, args);
|
|
2328 var exception, returnValue;
|
|
2329
|
|
2330 incrementCallCount.call(this);
|
|
2331 push.call(this.thisValues, thisValue);
|
|
2332 push.call(this.args, args);
|
|
2333 push.call(this.callIds, callId++);
|
|
2334
|
|
2335 // Make call properties available from within the spied function:
|
|
2336 createCallProperties.call(this);
|
|
2337
|
|
2338 try {
|
|
2339 this.invoking = true;
|
|
2340
|
|
2341 if (matching) {
|
|
2342 returnValue = matching.invoke(func, thisValue, args);
|
|
2343 } else {
|
|
2344 returnValue = (this.func || func).apply(thisValue, args);
|
|
2345 }
|
|
2346
|
|
2347 var thisCall = this.getCall(this.callCount - 1);
|
|
2348 if (thisCall.calledWithNew() && typeof returnValue !== "object") {
|
|
2349 returnValue = thisValue;
|
|
2350 }
|
|
2351 } catch (e) {
|
|
2352 exception = e;
|
|
2353 } finally {
|
|
2354 delete this.invoking;
|
|
2355 }
|
|
2356
|
|
2357 push.call(this.exceptions, exception);
|
|
2358 push.call(this.returnValues, returnValue);
|
|
2359
|
|
2360 // Make return value and exception available in the calls:
|
|
2361 createCallProperties.call(this);
|
|
2362
|
|
2363 if (exception !== undefined) {
|
|
2364 throw exception;
|
|
2365 }
|
|
2366
|
|
2367 return returnValue;
|
|
2368 },
|
|
2369
|
|
2370 named: function named(name) {
|
|
2371 this.displayName = name;
|
|
2372 return this;
|
|
2373 },
|
|
2374
|
|
2375 getCall: function getCall(i) {
|
|
2376 if (i < 0 || i >= this.callCount) {
|
|
2377 return null;
|
|
2378 }
|
|
2379
|
|
2380 return sinon.spyCall(this, this.thisValues[i], this.args[i],
|
|
2381 this.returnValues[i], this.exceptions[i],
|
|
2382 this.callIds[i]);
|
|
2383 },
|
|
2384
|
|
2385 getCalls: function () {
|
|
2386 var calls = [];
|
|
2387 var i;
|
|
2388
|
|
2389 for (i = 0; i < this.callCount; i++) {
|
|
2390 calls.push(this.getCall(i));
|
|
2391 }
|
|
2392
|
|
2393 return calls;
|
|
2394 },
|
|
2395
|
|
2396 calledBefore: function calledBefore(spyFn) {
|
|
2397 if (!this.called) {
|
|
2398 return false;
|
|
2399 }
|
|
2400
|
|
2401 if (!spyFn.called) {
|
|
2402 return true;
|
|
2403 }
|
|
2404
|
|
2405 return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
|
|
2406 },
|
|
2407
|
|
2408 calledAfter: function calledAfter(spyFn) {
|
|
2409 if (!this.called || !spyFn.called) {
|
|
2410 return false;
|
|
2411 }
|
|
2412
|
|
2413 return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
|
|
2414 },
|
|
2415
|
|
2416 withArgs: function () {
|
|
2417 var args = slice.call(arguments);
|
|
2418
|
|
2419 if (this.fakes) {
|
|
2420 var match = matchingFake(this.fakes, args, true);
|
|
2421
|
|
2422 if (match) {
|
|
2423 return match;
|
|
2424 }
|
|
2425 } else {
|
|
2426 this.fakes = [];
|
|
2427 }
|
|
2428
|
|
2429 var original = this;
|
|
2430 var fake = this.instantiateFake();
|
|
2431 fake.matchingAguments = args;
|
|
2432 fake.parent = this;
|
|
2433 push.call(this.fakes, fake);
|
|
2434
|
|
2435 fake.withArgs = function () {
|
|
2436 return original.withArgs.apply(original, arguments);
|
|
2437 };
|
|
2438
|
|
2439 for (var i = 0; i < this.args.length; i++) {
|
|
2440 if (fake.matches(this.args[i])) {
|
|
2441 incrementCallCount.call(fake);
|
|
2442 push.call(fake.thisValues, this.thisValues[i]);
|
|
2443 push.call(fake.args, this.args[i]);
|
|
2444 push.call(fake.returnValues, this.returnValues[i]);
|
|
2445 push.call(fake.exceptions, this.exceptions[i]);
|
|
2446 push.call(fake.callIds, this.callIds[i]);
|
|
2447 }
|
|
2448 }
|
|
2449 createCallProperties.call(fake);
|
|
2450
|
|
2451 return fake;
|
|
2452 },
|
|
2453
|
|
2454 matches: function (args, strict) {
|
|
2455 var margs = this.matchingAguments;
|
|
2456
|
|
2457 if (margs.length <= args.length &&
|
|
2458 sinon.deepEqual(margs, args.slice(0, margs.length))) {
|
|
2459 return !strict || margs.length == args.length;
|
|
2460 }
|
|
2461 },
|
|
2462
|
|
2463 printf: function (format) {
|
|
2464 var spy = this;
|
|
2465 var args = slice.call(arguments, 1);
|
|
2466 var formatter;
|
|
2467
|
|
2468 return (format || "").replace(/%(.)/g, function (match, specifyer) {
|
|
2469 formatter = spyApi.formatters[specifyer];
|
|
2470
|
|
2471 if (typeof formatter == "function") {
|
|
2472 return formatter.call(null, spy, args);
|
|
2473 } else if (!isNaN(parseInt(specifyer, 10))) {
|
|
2474 return sinon.format(args[specifyer - 1]);
|
|
2475 }
|
|
2476
|
|
2477 return "%" + specifyer;
|
|
2478 });
|
|
2479 }
|
|
2480 };
|
|
2481
|
|
2482 function delegateToCalls(method, matchAny, actual, notCalled) {
|
|
2483 spyApi[method] = function () {
|
|
2484 if (!this.called) {
|
|
2485 if (notCalled) {
|
|
2486 return notCalled.apply(this, arguments);
|
|
2487 }
|
|
2488 return false;
|
|
2489 }
|
|
2490
|
|
2491 var currentCall;
|
|
2492 var matches = 0;
|
|
2493
|
|
2494 for (var i = 0, l = this.callCount; i < l; i += 1) {
|
|
2495 currentCall = this.getCall(i);
|
|
2496
|
|
2497 if (currentCall[actual || method].apply(currentCall, arguments)) {
|
|
2498 matches += 1;
|
|
2499
|
|
2500 if (matchAny) {
|
|
2501 return true;
|
|
2502 }
|
|
2503 }
|
|
2504 }
|
|
2505
|
|
2506 return matches === this.callCount;
|
|
2507 };
|
|
2508 }
|
|
2509
|
|
2510 delegateToCalls("calledOn", true);
|
|
2511 delegateToCalls("alwaysCalledOn", false, "calledOn");
|
|
2512 delegateToCalls("calledWith", true);
|
|
2513 delegateToCalls("calledWithMatch", true);
|
|
2514 delegateToCalls("alwaysCalledWith", false, "calledWith");
|
|
2515 delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
|
|
2516 delegateToCalls("calledWithExactly", true);
|
|
2517 delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
|
|
2518 delegateToCalls("neverCalledWith", false, "notCalledWith",
|
|
2519 function () { return true; });
|
|
2520 delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
|
|
2521 function () { return true; });
|
|
2522 delegateToCalls("threw", true);
|
|
2523 delegateToCalls("alwaysThrew", false, "threw");
|
|
2524 delegateToCalls("returned", true);
|
|
2525 delegateToCalls("alwaysReturned", false, "returned");
|
|
2526 delegateToCalls("calledWithNew", true);
|
|
2527 delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
|
|
2528 delegateToCalls("callArg", false, "callArgWith", function () {
|
|
2529 throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
|
|
2530 });
|
|
2531 spyApi.callArgWith = spyApi.callArg;
|
|
2532 delegateToCalls("callArgOn", false, "callArgOnWith", function () {
|
|
2533 throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
|
|
2534 });
|
|
2535 spyApi.callArgOnWith = spyApi.callArgOn;
|
|
2536 delegateToCalls("yield", false, "yield", function () {
|
|
2537 throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
|
|
2538 });
|
|
2539 // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
|
|
2540 spyApi.invokeCallback = spyApi.yield;
|
|
2541 delegateToCalls("yieldOn", false, "yieldOn", function () {
|
|
2542 throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
|
|
2543 });
|
|
2544 delegateToCalls("yieldTo", false, "yieldTo", function (property) {
|
|
2545 throw new Error(this.toString() + " cannot yield to '" + property +
|
|
2546 "' since it was not yet invoked.");
|
|
2547 });
|
|
2548 delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
|
|
2549 throw new Error(this.toString() + " cannot yield to '" + property +
|
|
2550 "' since it was not yet invoked.");
|
|
2551 });
|
|
2552
|
|
2553 spyApi.formatters = {
|
|
2554 c: function (spy) {
|
|
2555 return sinon.timesInWords(spy.callCount);
|
|
2556 },
|
|
2557
|
|
2558 n: function (spy) {
|
|
2559 return spy.toString();
|
|
2560 },
|
|
2561
|
|
2562 C: function (spy) {
|
|
2563 var calls = [];
|
|
2564
|
|
2565 for (var i = 0, l = spy.callCount; i < l; ++i) {
|
|
2566 var stringifiedCall = " " + spy.getCall(i).toString();
|
|
2567 if (/\n/.test(calls[i - 1])) {
|
|
2568 stringifiedCall = "\n" + stringifiedCall;
|
|
2569 }
|
|
2570 push.call(calls, stringifiedCall);
|
|
2571 }
|
|
2572
|
|
2573 return calls.length > 0 ? "\n" + calls.join("\n") : "";
|
|
2574 },
|
|
2575
|
|
2576 t: function (spy) {
|
|
2577 var objects = [];
|
|
2578
|
|
2579 for (var i = 0, l = spy.callCount; i < l; ++i) {
|
|
2580 push.call(objects, sinon.format(spy.thisValues[i]));
|
|
2581 }
|
|
2582
|
|
2583 return objects.join(", ");
|
|
2584 },
|
|
2585
|
|
2586 "*": function (spy, args) {
|
|
2587 var formatted = [];
|
|
2588
|
|
2589 for (var i = 0, l = args.length; i < l; ++i) {
|
|
2590 push.call(formatted, sinon.format(args[i]));
|
|
2591 }
|
|
2592
|
|
2593 return formatted.join(", ");
|
|
2594 }
|
|
2595 };
|
|
2596
|
|
2597 sinon.extend(spy, spyApi);
|
|
2598
|
|
2599 spy.spyCall = sinon.spyCall;
|
|
2600 sinon.spy = spy;
|
|
2601
|
|
2602 return spy;
|
|
2603 }
|
|
2604
|
|
2605 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
2606 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
2607
|
|
2608 function loadDependencies(require, exports, module) {
|
|
2609 var sinon = require("./util/core");
|
|
2610 require("./call");
|
|
2611 module.exports = makeApi(sinon);
|
|
2612 }
|
|
2613
|
|
2614 if (isAMD) {
|
|
2615 define(loadDependencies);
|
|
2616 } else if (isNode) {
|
|
2617 loadDependencies(require, module.exports, module);
|
|
2618 } else if (!sinon) {
|
|
2619 return;
|
|
2620 } else {
|
|
2621 makeApi(sinon);
|
|
2622 }
|
|
2623 }(typeof sinon == "object" && sinon || null));
|
|
2624
|
|
2625 /**
|
|
2626 * @depend util/core.js
|
|
2627 * @depend extend.js
|
|
2628 */
|
|
2629 /**
|
|
2630 * Stub behavior
|
|
2631 *
|
|
2632 * @author Christian Johansen ([email protected])
|
|
2633 * @author Tim Fischbach ([email protected])
|
|
2634 * @license BSD
|
|
2635 *
|
|
2636 * Copyright (c) 2010-2013 Christian Johansen
|
|
2637 */
|
|
2638
|
|
2639 (function (sinon) {
|
|
2640 var slice = Array.prototype.slice;
|
|
2641 var join = Array.prototype.join;
|
|
2642
|
|
2643 var nextTick = (function () {
|
|
2644 if (typeof process === "object" && typeof process.nextTick === "function") {
|
|
2645 return process.nextTick;
|
|
2646 } else if (typeof setImmediate === "function") {
|
|
2647 return setImmediate;
|
|
2648 } else {
|
|
2649 return function (callback) {
|
|
2650 setTimeout(callback, 0);
|
|
2651 };
|
|
2652 }
|
|
2653 })();
|
|
2654
|
|
2655 function throwsException(error, message) {
|
|
2656 if (typeof error == "string") {
|
|
2657 this.exception = new Error(message || "");
|
|
2658 this.exception.name = error;
|
|
2659 } else if (!error) {
|
|
2660 this.exception = new Error("Error");
|
|
2661 } else {
|
|
2662 this.exception = error;
|
|
2663 }
|
|
2664
|
|
2665 return this;
|
|
2666 }
|
|
2667
|
|
2668 function getCallback(behavior, args) {
|
|
2669 var callArgAt = behavior.callArgAt;
|
|
2670
|
|
2671 if (callArgAt < 0) {
|
|
2672 var callArgProp = behavior.callArgProp;
|
|
2673
|
|
2674 for (var i = 0, l = args.length; i < l; ++i) {
|
|
2675 if (!callArgProp && typeof args[i] == "function") {
|
|
2676 return args[i];
|
|
2677 }
|
|
2678
|
|
2679 if (callArgProp && args[i] &&
|
|
2680 typeof args[i][callArgProp] == "function") {
|
|
2681 return args[i][callArgProp];
|
|
2682 }
|
|
2683 }
|
|
2684
|
|
2685 return null;
|
|
2686 }
|
|
2687
|
|
2688 return args[callArgAt];
|
|
2689 }
|
|
2690
|
|
2691 function makeApi(sinon) {
|
|
2692 function getCallbackError(behavior, func, args) {
|
|
2693 if (behavior.callArgAt < 0) {
|
|
2694 var msg;
|
|
2695
|
|
2696 if (behavior.callArgProp) {
|
|
2697 msg = sinon.functionName(behavior.stub) +
|
|
2698 " expected to yield to '" + behavior.callArgProp +
|
|
2699 "', but no object with such a property was passed.";
|
|
2700 } else {
|
|
2701 msg = sinon.functionName(behavior.stub) +
|
|
2702 " expected to yield, but no callback was passed.";
|
|
2703 }
|
|
2704
|
|
2705 if (args.length > 0) {
|
|
2706 msg += " Received [" + join.call(args, ", ") + "]";
|
|
2707 }
|
|
2708
|
|
2709 return msg;
|
|
2710 }
|
|
2711
|
|
2712 return "argument at index " + behavior.callArgAt + " is not a function: " + func;
|
|
2713 }
|
|
2714
|
|
2715 function callCallback(behavior, args) {
|
|
2716 if (typeof behavior.callArgAt == "number") {
|
|
2717 var func = getCallback(behavior, args);
|
|
2718
|
|
2719 if (typeof func != "function") {
|
|
2720 throw new TypeError(getCallbackError(behavior, func, args));
|
|
2721 }
|
|
2722
|
|
2723 if (behavior.callbackAsync) {
|
|
2724 nextTick(function () {
|
|
2725 func.apply(behavior.callbackContext, behavior.callbackArguments);
|
|
2726 });
|
|
2727 } else {
|
|
2728 func.apply(behavior.callbackContext, behavior.callbackArguments);
|
|
2729 }
|
|
2730 }
|
|
2731 }
|
|
2732
|
|
2733 var proto = {
|
|
2734 create: function create(stub) {
|
|
2735 var behavior = sinon.extend({}, sinon.behavior);
|
|
2736 delete behavior.create;
|
|
2737 behavior.stub = stub;
|
|
2738
|
|
2739 return behavior;
|
|
2740 },
|
|
2741
|
|
2742 isPresent: function isPresent() {
|
|
2743 return (typeof this.callArgAt == "number" ||
|
|
2744 this.exception ||
|
|
2745 typeof this.returnArgAt == "number" ||
|
|
2746 this.returnThis ||
|
|
2747 this.returnValueDefined);
|
|
2748 },
|
|
2749
|
|
2750 invoke: function invoke(context, args) {
|
|
2751 callCallback(this, args);
|
|
2752
|
|
2753 if (this.exception) {
|
|
2754 throw this.exception;
|
|
2755 } else if (typeof this.returnArgAt == "number") {
|
|
2756 return args[this.returnArgAt];
|
|
2757 } else if (this.returnThis) {
|
|
2758 return context;
|
|
2759 }
|
|
2760
|
|
2761 return this.returnValue;
|
|
2762 },
|
|
2763
|
|
2764 onCall: function onCall(index) {
|
|
2765 return this.stub.onCall(index);
|
|
2766 },
|
|
2767
|
|
2768 onFirstCall: function onFirstCall() {
|
|
2769 return this.stub.onFirstCall();
|
|
2770 },
|
|
2771
|
|
2772 onSecondCall: function onSecondCall() {
|
|
2773 return this.stub.onSecondCall();
|
|
2774 },
|
|
2775
|
|
2776 onThirdCall: function onThirdCall() {
|
|
2777 return this.stub.onThirdCall();
|
|
2778 },
|
|
2779
|
|
2780 withArgs: function withArgs(/* arguments */) {
|
|
2781 throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " +
|
|
2782 "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments.");
|
|
2783 },
|
|
2784
|
|
2785 callsArg: function callsArg(pos) {
|
|
2786 if (typeof pos != "number") {
|
|
2787 throw new TypeError("argument index is not number");
|
|
2788 }
|
|
2789
|
|
2790 this.callArgAt = pos;
|
|
2791 this.callbackArguments = [];
|
|
2792 this.callbackContext = undefined;
|
|
2793 this.callArgProp = undefined;
|
|
2794 this.callbackAsync = false;
|
|
2795
|
|
2796 return this;
|
|
2797 },
|
|
2798
|
|
2799 callsArgOn: function callsArgOn(pos, context) {
|
|
2800 if (typeof pos != "number") {
|
|
2801 throw new TypeError("argument index is not number");
|
|
2802 }
|
|
2803 if (typeof context != "object") {
|
|
2804 throw new TypeError("argument context is not an object");
|
|
2805 }
|
|
2806
|
|
2807 this.callArgAt = pos;
|
|
2808 this.callbackArguments = [];
|
|
2809 this.callbackContext = context;
|
|
2810 this.callArgProp = undefined;
|
|
2811 this.callbackAsync = false;
|
|
2812
|
|
2813 return this;
|
|
2814 },
|
|
2815
|
|
2816 callsArgWith: function callsArgWith(pos) {
|
|
2817 if (typeof pos != "number") {
|
|
2818 throw new TypeError("argument index is not number");
|
|
2819 }
|
|
2820
|
|
2821 this.callArgAt = pos;
|
|
2822 this.callbackArguments = slice.call(arguments, 1);
|
|
2823 this.callbackContext = undefined;
|
|
2824 this.callArgProp = undefined;
|
|
2825 this.callbackAsync = false;
|
|
2826
|
|
2827 return this;
|
|
2828 },
|
|
2829
|
|
2830 callsArgOnWith: function callsArgWith(pos, context) {
|
|
2831 if (typeof pos != "number") {
|
|
2832 throw new TypeError("argument index is not number");
|
|
2833 }
|
|
2834 if (typeof context != "object") {
|
|
2835 throw new TypeError("argument context is not an object");
|
|
2836 }
|
|
2837
|
|
2838 this.callArgAt = pos;
|
|
2839 this.callbackArguments = slice.call(arguments, 2);
|
|
2840 this.callbackContext = context;
|
|
2841 this.callArgProp = undefined;
|
|
2842 this.callbackAsync = false;
|
|
2843
|
|
2844 return this;
|
|
2845 },
|
|
2846
|
|
2847 yields: function () {
|
|
2848 this.callArgAt = -1;
|
|
2849 this.callbackArguments = slice.call(arguments, 0);
|
|
2850 this.callbackContext = undefined;
|
|
2851 this.callArgProp = undefined;
|
|
2852 this.callbackAsync = false;
|
|
2853
|
|
2854 return this;
|
|
2855 },
|
|
2856
|
|
2857 yieldsOn: function (context) {
|
|
2858 if (typeof context != "object") {
|
|
2859 throw new TypeError("argument context is not an object");
|
|
2860 }
|
|
2861
|
|
2862 this.callArgAt = -1;
|
|
2863 this.callbackArguments = slice.call(arguments, 1);
|
|
2864 this.callbackContext = context;
|
|
2865 this.callArgProp = undefined;
|
|
2866 this.callbackAsync = false;
|
|
2867
|
|
2868 return this;
|
|
2869 },
|
|
2870
|
|
2871 yieldsTo: function (prop) {
|
|
2872 this.callArgAt = -1;
|
|
2873 this.callbackArguments = slice.call(arguments, 1);
|
|
2874 this.callbackContext = undefined;
|
|
2875 this.callArgProp = prop;
|
|
2876 this.callbackAsync = false;
|
|
2877
|
|
2878 return this;
|
|
2879 },
|
|
2880
|
|
2881 yieldsToOn: function (prop, context) {
|
|
2882 if (typeof context != "object") {
|
|
2883 throw new TypeError("argument context is not an object");
|
|
2884 }
|
|
2885
|
|
2886 this.callArgAt = -1;
|
|
2887 this.callbackArguments = slice.call(arguments, 2);
|
|
2888 this.callbackContext = context;
|
|
2889 this.callArgProp = prop;
|
|
2890 this.callbackAsync = false;
|
|
2891
|
|
2892 return this;
|
|
2893 },
|
|
2894
|
|
2895 throws: throwsException,
|
|
2896 throwsException: throwsException,
|
|
2897
|
|
2898 returns: function returns(value) {
|
|
2899 this.returnValue = value;
|
|
2900 this.returnValueDefined = true;
|
|
2901
|
|
2902 return this;
|
|
2903 },
|
|
2904
|
|
2905 returnsArg: function returnsArg(pos) {
|
|
2906 if (typeof pos != "number") {
|
|
2907 throw new TypeError("argument index is not number");
|
|
2908 }
|
|
2909
|
|
2910 this.returnArgAt = pos;
|
|
2911
|
|
2912 return this;
|
|
2913 },
|
|
2914
|
|
2915 returnsThis: function returnsThis() {
|
|
2916 this.returnThis = true;
|
|
2917
|
|
2918 return this;
|
|
2919 }
|
|
2920 };
|
|
2921
|
|
2922 // create asynchronous versions of callsArg* and yields* methods
|
|
2923 for (var method in proto) {
|
|
2924 // need to avoid creating anotherasync versions of the newly added async methods
|
|
2925 if (proto.hasOwnProperty(method) &&
|
|
2926 method.match(/^(callsArg|yields)/) &&
|
|
2927 !method.match(/Async/)) {
|
|
2928 proto[method + "Async"] = (function (syncFnName) {
|
|
2929 return function () {
|
|
2930 var result = this[syncFnName].apply(this, arguments);
|
|
2931 this.callbackAsync = true;
|
|
2932 return result;
|
|
2933 };
|
|
2934 })(method);
|
|
2935 }
|
|
2936 }
|
|
2937
|
|
2938 sinon.behavior = proto;
|
|
2939 return proto;
|
|
2940 }
|
|
2941
|
|
2942 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
2943 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
2944
|
|
2945 function loadDependencies(require, exports, module) {
|
|
2946 var sinon = require("./util/core");
|
|
2947 module.exports = makeApi(sinon);
|
|
2948 }
|
|
2949
|
|
2950 if (isAMD) {
|
|
2951 define(loadDependencies);
|
|
2952 } else if (isNode) {
|
|
2953 loadDependencies(require, module.exports, module);
|
|
2954 } else if (!sinon) {
|
|
2955 return;
|
|
2956 } else {
|
|
2957 makeApi(sinon);
|
|
2958 }
|
|
2959 }(typeof sinon == "object" && sinon || null));
|
|
2960
|
|
2961 /**
|
|
2962 * @depend util/core.js
|
|
2963 * @depend extend.js
|
|
2964 * @depend spy.js
|
|
2965 * @depend behavior.js
|
|
2966 */
|
|
2967 /**
|
|
2968 * Stub functions
|
|
2969 *
|
|
2970 * @author Christian Johansen ([email protected])
|
|
2971 * @license BSD
|
|
2972 *
|
|
2973 * Copyright (c) 2010-2013 Christian Johansen
|
|
2974 */
|
|
2975
|
|
2976 (function (sinon) {
|
|
2977 function makeApi(sinon) {
|
|
2978 function stub(object, property, func) {
|
|
2979 if (!!func && typeof func != "function") {
|
|
2980 throw new TypeError("Custom stub should be function");
|
|
2981 }
|
|
2982
|
|
2983 var wrapper;
|
|
2984
|
|
2985 if (func) {
|
|
2986 wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
|
|
2987 } else {
|
|
2988 wrapper = stub.create();
|
|
2989 }
|
|
2990
|
|
2991 if (!object && typeof property === "undefined") {
|
|
2992 return sinon.stub.create();
|
|
2993 }
|
|
2994
|
|
2995 if (typeof property === "undefined" && typeof object == "object") {
|
|
2996 for (var prop in object) {
|
|
2997 if (typeof object[prop] === "function") {
|
|
2998 stub(object, prop);
|
|
2999 }
|
|
3000 }
|
|
3001
|
|
3002 return object;
|
|
3003 }
|
|
3004
|
|
3005 return sinon.wrapMethod(object, property, wrapper);
|
|
3006 }
|
|
3007
|
|
3008 function getDefaultBehavior(stub) {
|
|
3009 return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
|
|
3010 }
|
|
3011
|
|
3012 function getParentBehaviour(stub) {
|
|
3013 return (stub.parent && getCurrentBehavior(stub.parent));
|
|
3014 }
|
|
3015
|
|
3016 function getCurrentBehavior(stub) {
|
|
3017 var behavior = stub.behaviors[stub.callCount - 1];
|
|
3018 return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
|
|
3019 }
|
|
3020
|
|
3021 var uuid = 0;
|
|
3022
|
|
3023 var proto = {
|
|
3024 create: function create() {
|
|
3025 var functionStub = function () {
|
|
3026 return getCurrentBehavior(functionStub).invoke(this, arguments);
|
|
3027 };
|
|
3028
|
|
3029 functionStub.id = "stub#" + uuid++;
|
|
3030 var orig = functionStub;
|
|
3031 functionStub = sinon.spy.create(functionStub);
|
|
3032 functionStub.func = orig;
|
|
3033
|
|
3034 sinon.extend(functionStub, stub);
|
|
3035 functionStub.instantiateFake = sinon.stub.create;
|
|
3036 functionStub.displayName = "stub";
|
|
3037 functionStub.toString = sinon.functionToString;
|
|
3038
|
|
3039 functionStub.defaultBehavior = null;
|
|
3040 functionStub.behaviors = [];
|
|
3041
|
|
3042 return functionStub;
|
|
3043 },
|
|
3044
|
|
3045 resetBehavior: function () {
|
|
3046 var i;
|
|
3047
|
|
3048 this.defaultBehavior = null;
|
|
3049 this.behaviors = [];
|
|
3050
|
|
3051 delete this.returnValue;
|
|
3052 delete this.returnArgAt;
|
|
3053 this.returnThis = false;
|
|
3054
|
|
3055 if (this.fakes) {
|
|
3056 for (i = 0; i < this.fakes.length; i++) {
|
|
3057 this.fakes[i].resetBehavior();
|
|
3058 }
|
|
3059 }
|
|
3060 },
|
|
3061
|
|
3062 onCall: function onCall(index) {
|
|
3063 if (!this.behaviors[index]) {
|
|
3064 this.behaviors[index] = sinon.behavior.create(this);
|
|
3065 }
|
|
3066
|
|
3067 return this.behaviors[index];
|
|
3068 },
|
|
3069
|
|
3070 onFirstCall: function onFirstCall() {
|
|
3071 return this.onCall(0);
|
|
3072 },
|
|
3073
|
|
3074 onSecondCall: function onSecondCall() {
|
|
3075 return this.onCall(1);
|
|
3076 },
|
|
3077
|
|
3078 onThirdCall: function onThirdCall() {
|
|
3079 return this.onCall(2);
|
|
3080 }
|
|
3081 };
|
|
3082
|
|
3083 for (var method in sinon.behavior) {
|
|
3084 if (sinon.behavior.hasOwnProperty(method) &&
|
|
3085 !proto.hasOwnProperty(method) &&
|
|
3086 method != "create" &&
|
|
3087 method != "withArgs" &&
|
|
3088 method != "invoke") {
|
|
3089 proto[method] = (function (behaviorMethod) {
|
|
3090 return function () {
|
|
3091 this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
|
|
3092 this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
|
|
3093 return this;
|
|
3094 };
|
|
3095 }(method));
|
|
3096 }
|
|
3097 }
|
|
3098
|
|
3099 sinon.extend(stub, proto);
|
|
3100 sinon.stub = stub;
|
|
3101
|
|
3102 return stub;
|
|
3103 }
|
|
3104
|
|
3105 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3106 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3107
|
|
3108 function loadDependencies(require, exports, module) {
|
|
3109 var sinon = require("./util/core");
|
|
3110 require("./behavior");
|
|
3111 require("./spy");
|
|
3112 module.exports = makeApi(sinon);
|
|
3113 }
|
|
3114
|
|
3115 if (isAMD) {
|
|
3116 define(loadDependencies);
|
|
3117 } else if (isNode) {
|
|
3118 loadDependencies(require, module.exports, module);
|
|
3119 } else if (!sinon) {
|
|
3120 return;
|
|
3121 } else {
|
|
3122 makeApi(sinon);
|
|
3123 }
|
|
3124 }(typeof sinon == "object" && sinon || null));
|
|
3125
|
|
3126 /**
|
|
3127 * @depend times_in_words.js
|
|
3128 * @depend util/core.js
|
|
3129 * @depend extend.js
|
|
3130 * @depend stub.js
|
|
3131 * @depend format.js
|
|
3132 */
|
|
3133 /**
|
|
3134 * Mock functions.
|
|
3135 *
|
|
3136 * @author Christian Johansen ([email protected])
|
|
3137 * @license BSD
|
|
3138 *
|
|
3139 * Copyright (c) 2010-2013 Christian Johansen
|
|
3140 */
|
|
3141
|
|
3142 (function (sinon) {
|
|
3143 function makeApi(sinon) {
|
|
3144 var push = [].push;
|
|
3145 var match = sinon.match;
|
|
3146
|
|
3147 function mock(object) {
|
|
3148 if (!object) {
|
|
3149 return sinon.expectation.create("Anonymous mock");
|
|
3150 }
|
|
3151
|
|
3152 return mock.create(object);
|
|
3153 }
|
|
3154
|
|
3155 function each(collection, callback) {
|
|
3156 if (!collection) {
|
|
3157 return;
|
|
3158 }
|
|
3159
|
|
3160 for (var i = 0, l = collection.length; i < l; i += 1) {
|
|
3161 callback(collection[i]);
|
|
3162 }
|
|
3163 }
|
|
3164
|
|
3165 sinon.extend(mock, {
|
|
3166 create: function create(object) {
|
|
3167 if (!object) {
|
|
3168 throw new TypeError("object is null");
|
|
3169 }
|
|
3170
|
|
3171 var mockObject = sinon.extend({}, mock);
|
|
3172 mockObject.object = object;
|
|
3173 delete mockObject.create;
|
|
3174
|
|
3175 return mockObject;
|
|
3176 },
|
|
3177
|
|
3178 expects: function expects(method) {
|
|
3179 if (!method) {
|
|
3180 throw new TypeError("method is falsy");
|
|
3181 }
|
|
3182
|
|
3183 if (!this.expectations) {
|
|
3184 this.expectations = {};
|
|
3185 this.proxies = [];
|
|
3186 }
|
|
3187
|
|
3188 if (!this.expectations[method]) {
|
|
3189 this.expectations[method] = [];
|
|
3190 var mockObject = this;
|
|
3191
|
|
3192 sinon.wrapMethod(this.object, method, function () {
|
|
3193 return mockObject.invokeMethod(method, this, arguments);
|
|
3194 });
|
|
3195
|
|
3196 push.call(this.proxies, method);
|
|
3197 }
|
|
3198
|
|
3199 var expectation = sinon.expectation.create(method);
|
|
3200 push.call(this.expectations[method], expectation);
|
|
3201
|
|
3202 return expectation;
|
|
3203 },
|
|
3204
|
|
3205 restore: function restore() {
|
|
3206 var object = this.object;
|
|
3207
|
|
3208 each(this.proxies, function (proxy) {
|
|
3209 if (typeof object[proxy].restore == "function") {
|
|
3210 object[proxy].restore();
|
|
3211 }
|
|
3212 });
|
|
3213 },
|
|
3214
|
|
3215 verify: function verify() {
|
|
3216 var expectations = this.expectations || {};
|
|
3217 var messages = [], met = [];
|
|
3218
|
|
3219 each(this.proxies, function (proxy) {
|
|
3220 each(expectations[proxy], function (expectation) {
|
|
3221 if (!expectation.met()) {
|
|
3222 push.call(messages, expectation.toString());
|
|
3223 } else {
|
|
3224 push.call(met, expectation.toString());
|
|
3225 }
|
|
3226 });
|
|
3227 });
|
|
3228
|
|
3229 this.restore();
|
|
3230
|
|
3231 if (messages.length > 0) {
|
|
3232 sinon.expectation.fail(messages.concat(met).join("\n"));
|
|
3233 } else if (met.length > 0) {
|
|
3234 sinon.expectation.pass(messages.concat(met).join("\n"));
|
|
3235 }
|
|
3236
|
|
3237 return true;
|
|
3238 },
|
|
3239
|
|
3240 invokeMethod: function invokeMethod(method, thisValue, args) {
|
|
3241 var expectations = this.expectations && this.expectations[method];
|
|
3242 var length = expectations && expectations.length || 0, i;
|
|
3243
|
|
3244 for (i = 0; i < length; i += 1) {
|
|
3245 if (!expectations[i].met() &&
|
|
3246 expectations[i].allowsCall(thisValue, args)) {
|
|
3247 return expectations[i].apply(thisValue, args);
|
|
3248 }
|
|
3249 }
|
|
3250
|
|
3251 var messages = [], available, exhausted = 0;
|
|
3252
|
|
3253 for (i = 0; i < length; i += 1) {
|
|
3254 if (expectations[i].allowsCall(thisValue, args)) {
|
|
3255 available = available || expectations[i];
|
|
3256 } else {
|
|
3257 exhausted += 1;
|
|
3258 }
|
|
3259 push.call(messages, " " + expectations[i].toString());
|
|
3260 }
|
|
3261
|
|
3262 if (exhausted === 0) {
|
|
3263 return available.apply(thisValue, args);
|
|
3264 }
|
|
3265
|
|
3266 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
|
|
3267 proxy: method,
|
|
3268 args: args
|
|
3269 }));
|
|
3270
|
|
3271 sinon.expectation.fail(messages.join("\n"));
|
|
3272 }
|
|
3273 });
|
|
3274
|
|
3275 var times = sinon.timesInWords;
|
|
3276 var slice = Array.prototype.slice;
|
|
3277
|
|
3278 function callCountInWords(callCount) {
|
|
3279 if (callCount == 0) {
|
|
3280 return "never called";
|
|
3281 } else {
|
|
3282 return "called " + times(callCount);
|
|
3283 }
|
|
3284 }
|
|
3285
|
|
3286 function expectedCallCountInWords(expectation) {
|
|
3287 var min = expectation.minCalls;
|
|
3288 var max = expectation.maxCalls;
|
|
3289
|
|
3290 if (typeof min == "number" && typeof max == "number") {
|
|
3291 var str = times(min);
|
|
3292
|
|
3293 if (min != max) {
|
|
3294 str = "at least " + str + " and at most " + times(max);
|
|
3295 }
|
|
3296
|
|
3297 return str;
|
|
3298 }
|
|
3299
|
|
3300 if (typeof min == "number") {
|
|
3301 return "at least " + times(min);
|
|
3302 }
|
|
3303
|
|
3304 return "at most " + times(max);
|
|
3305 }
|
|
3306
|
|
3307 function receivedMinCalls(expectation) {
|
|
3308 var hasMinLimit = typeof expectation.minCalls == "number";
|
|
3309 return !hasMinLimit || expectation.callCount >= expectation.minCalls;
|
|
3310 }
|
|
3311
|
|
3312 function receivedMaxCalls(expectation) {
|
|
3313 if (typeof expectation.maxCalls != "number") {
|
|
3314 return false;
|
|
3315 }
|
|
3316
|
|
3317 return expectation.callCount == expectation.maxCalls;
|
|
3318 }
|
|
3319
|
|
3320 function verifyMatcher(possibleMatcher, arg) {
|
|
3321 if (match && match.isMatcher(possibleMatcher)) {
|
|
3322 return possibleMatcher.test(arg);
|
|
3323 } else {
|
|
3324 return true;
|
|
3325 }
|
|
3326 }
|
|
3327
|
|
3328 sinon.expectation = {
|
|
3329 minCalls: 1,
|
|
3330 maxCalls: 1,
|
|
3331
|
|
3332 create: function create(methodName) {
|
|
3333 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
|
|
3334 delete expectation.create;
|
|
3335 expectation.method = methodName;
|
|
3336
|
|
3337 return expectation;
|
|
3338 },
|
|
3339
|
|
3340 invoke: function invoke(func, thisValue, args) {
|
|
3341 this.verifyCallAllowed(thisValue, args);
|
|
3342
|
|
3343 return sinon.spy.invoke.apply(this, arguments);
|
|
3344 },
|
|
3345
|
|
3346 atLeast: function atLeast(num) {
|
|
3347 if (typeof num != "number") {
|
|
3348 throw new TypeError("'" + num + "' is not number");
|
|
3349 }
|
|
3350
|
|
3351 if (!this.limitsSet) {
|
|
3352 this.maxCalls = null;
|
|
3353 this.limitsSet = true;
|
|
3354 }
|
|
3355
|
|
3356 this.minCalls = num;
|
|
3357
|
|
3358 return this;
|
|
3359 },
|
|
3360
|
|
3361 atMost: function atMost(num) {
|
|
3362 if (typeof num != "number") {
|
|
3363 throw new TypeError("'" + num + "' is not number");
|
|
3364 }
|
|
3365
|
|
3366 if (!this.limitsSet) {
|
|
3367 this.minCalls = null;
|
|
3368 this.limitsSet = true;
|
|
3369 }
|
|
3370
|
|
3371 this.maxCalls = num;
|
|
3372
|
|
3373 return this;
|
|
3374 },
|
|
3375
|
|
3376 never: function never() {
|
|
3377 return this.exactly(0);
|
|
3378 },
|
|
3379
|
|
3380 once: function once() {
|
|
3381 return this.exactly(1);
|
|
3382 },
|
|
3383
|
|
3384 twice: function twice() {
|
|
3385 return this.exactly(2);
|
|
3386 },
|
|
3387
|
|
3388 thrice: function thrice() {
|
|
3389 return this.exactly(3);
|
|
3390 },
|
|
3391
|
|
3392 exactly: function exactly(num) {
|
|
3393 if (typeof num != "number") {
|
|
3394 throw new TypeError("'" + num + "' is not a number");
|
|
3395 }
|
|
3396
|
|
3397 this.atLeast(num);
|
|
3398 return this.atMost(num);
|
|
3399 },
|
|
3400
|
|
3401 met: function met() {
|
|
3402 return !this.failed && receivedMinCalls(this);
|
|
3403 },
|
|
3404
|
|
3405 verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
|
|
3406 if (receivedMaxCalls(this)) {
|
|
3407 this.failed = true;
|
|
3408 sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
|
|
3409 }
|
|
3410
|
|
3411 if ("expectedThis" in this && this.expectedThis !== thisValue) {
|
|
3412 sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
|
|
3413 this.expectedThis);
|
|
3414 }
|
|
3415
|
|
3416 if (!("expectedArguments" in this)) {
|
|
3417 return;
|
|
3418 }
|
|
3419
|
|
3420 if (!args) {
|
|
3421 sinon.expectation.fail(this.method + " received no arguments, expected " +
|
|
3422 sinon.format(this.expectedArguments));
|
|
3423 }
|
|
3424
|
|
3425 if (args.length < this.expectedArguments.length) {
|
|
3426 sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
|
|
3427 "), expected " + sinon.format(this.expectedArguments));
|
|
3428 }
|
|
3429
|
|
3430 if (this.expectsExactArgCount &&
|
|
3431 args.length != this.expectedArguments.length) {
|
|
3432 sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
|
|
3433 "), expected " + sinon.format(this.expectedArguments));
|
|
3434 }
|
|
3435
|
|
3436 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
|
|
3437
|
|
3438 if (!verifyMatcher(this.expectedArguments[i], args[i])) {
|
|
3439 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
|
|
3440 ", didn't match " + this.expectedArguments.toString());
|
|
3441 }
|
|
3442
|
|
3443 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
|
|
3444 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
|
|
3445 ", expected " + sinon.format(this.expectedArguments));
|
|
3446 }
|
|
3447 }
|
|
3448 },
|
|
3449
|
|
3450 allowsCall: function allowsCall(thisValue, args) {
|
|
3451 if (this.met() && receivedMaxCalls(this)) {
|
|
3452 return false;
|
|
3453 }
|
|
3454
|
|
3455 if ("expectedThis" in this && this.expectedThis !== thisValue) {
|
|
3456 return false;
|
|
3457 }
|
|
3458
|
|
3459 if (!("expectedArguments" in this)) {
|
|
3460 return true;
|
|
3461 }
|
|
3462
|
|
3463 args = args || [];
|
|
3464
|
|
3465 if (args.length < this.expectedArguments.length) {
|
|
3466 return false;
|
|
3467 }
|
|
3468
|
|
3469 if (this.expectsExactArgCount &&
|
|
3470 args.length != this.expectedArguments.length) {
|
|
3471 return false;
|
|
3472 }
|
|
3473
|
|
3474 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
|
|
3475 if (!verifyMatcher(this.expectedArguments[i], args[i])) {
|
|
3476 return false;
|
|
3477 }
|
|
3478
|
|
3479 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
|
|
3480 return false;
|
|
3481 }
|
|
3482 }
|
|
3483
|
|
3484 return true;
|
|
3485 },
|
|
3486
|
|
3487 withArgs: function withArgs() {
|
|
3488 this.expectedArguments = slice.call(arguments);
|
|
3489 return this;
|
|
3490 },
|
|
3491
|
|
3492 withExactArgs: function withExactArgs() {
|
|
3493 this.withArgs.apply(this, arguments);
|
|
3494 this.expectsExactArgCount = true;
|
|
3495 return this;
|
|
3496 },
|
|
3497
|
|
3498 on: function on(thisValue) {
|
|
3499 this.expectedThis = thisValue;
|
|
3500 return this;
|
|
3501 },
|
|
3502
|
|
3503 toString: function () {
|
|
3504 var args = (this.expectedArguments || []).slice();
|
|
3505
|
|
3506 if (!this.expectsExactArgCount) {
|
|
3507 push.call(args, "[...]");
|
|
3508 }
|
|
3509
|
|
3510 var callStr = sinon.spyCall.toString.call({
|
|
3511 proxy: this.method || "anonymous mock expectation",
|
|
3512 args: args
|
|
3513 });
|
|
3514
|
|
3515 var message = callStr.replace(", [...", "[, ...") + " " +
|
|
3516 expectedCallCountInWords(this);
|
|
3517
|
|
3518 if (this.met()) {
|
|
3519 return "Expectation met: " + message;
|
|
3520 }
|
|
3521
|
|
3522 return "Expected " + message + " (" +
|
|
3523 callCountInWords(this.callCount) + ")";
|
|
3524 },
|
|
3525
|
|
3526 verify: function verify() {
|
|
3527 if (!this.met()) {
|
|
3528 sinon.expectation.fail(this.toString());
|
|
3529 } else {
|
|
3530 sinon.expectation.pass(this.toString());
|
|
3531 }
|
|
3532
|
|
3533 return true;
|
|
3534 },
|
|
3535
|
|
3536 pass: function pass(message) {
|
|
3537 sinon.assert.pass(message);
|
|
3538 },
|
|
3539
|
|
3540 fail: function fail(message) {
|
|
3541 var exception = new Error(message);
|
|
3542 exception.name = "ExpectationError";
|
|
3543
|
|
3544 throw exception;
|
|
3545 }
|
|
3546 };
|
|
3547
|
|
3548 sinon.mock = mock;
|
|
3549 return mock;
|
|
3550 }
|
|
3551
|
|
3552 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3553 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3554
|
|
3555 function loadDependencies(require, exports, module) {
|
|
3556 var sinon = require("./util/core");
|
|
3557 require("./call");
|
|
3558 require("./match");
|
|
3559 require("./spy");
|
|
3560 module.exports = makeApi(sinon);
|
|
3561 }
|
|
3562
|
|
3563 if (isAMD) {
|
|
3564 define(loadDependencies);
|
|
3565 } else if (isNode) {
|
|
3566 loadDependencies(require, module.exports, module);
|
|
3567 } else if (!sinon) {
|
|
3568 return;
|
|
3569 } else {
|
|
3570 makeApi(sinon);
|
|
3571 }
|
|
3572 }(typeof sinon == "object" && sinon || null));
|
|
3573
|
|
3574 /**
|
|
3575 * @depend util/core.js
|
|
3576 * @depend stub.js
|
|
3577 * @depend mock.js
|
|
3578 */
|
|
3579 /**
|
|
3580 * Collections of stubs, spies and mocks.
|
|
3581 *
|
|
3582 * @author Christian Johansen ([email protected])
|
|
3583 * @license BSD
|
|
3584 *
|
|
3585 * Copyright (c) 2010-2013 Christian Johansen
|
|
3586 */
|
|
3587
|
|
3588 (function (sinon) {
|
|
3589 var push = [].push;
|
|
3590 var hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
3591
|
|
3592 function getFakes(fakeCollection) {
|
|
3593 if (!fakeCollection.fakes) {
|
|
3594 fakeCollection.fakes = [];
|
|
3595 }
|
|
3596
|
|
3597 return fakeCollection.fakes;
|
|
3598 }
|
|
3599
|
|
3600 function each(fakeCollection, method) {
|
|
3601 var fakes = getFakes(fakeCollection);
|
|
3602
|
|
3603 for (var i = 0, l = fakes.length; i < l; i += 1) {
|
|
3604 if (typeof fakes[i][method] == "function") {
|
|
3605 fakes[i][method]();
|
|
3606 }
|
|
3607 }
|
|
3608 }
|
|
3609
|
|
3610 function compact(fakeCollection) {
|
|
3611 var fakes = getFakes(fakeCollection);
|
|
3612 var i = 0;
|
|
3613 while (i < fakes.length) {
|
|
3614 fakes.splice(i, 1);
|
|
3615 }
|
|
3616 }
|
|
3617
|
|
3618 function makeApi(sinon) {
|
|
3619 var collection = {
|
|
3620 verify: function resolve() {
|
|
3621 each(this, "verify");
|
|
3622 },
|
|
3623
|
|
3624 restore: function restore() {
|
|
3625 each(this, "restore");
|
|
3626 compact(this);
|
|
3627 },
|
|
3628
|
|
3629 reset: function restore() {
|
|
3630 each(this, "reset");
|
|
3631 },
|
|
3632
|
|
3633 verifyAndRestore: function verifyAndRestore() {
|
|
3634 var exception;
|
|
3635
|
|
3636 try {
|
|
3637 this.verify();
|
|
3638 } catch (e) {
|
|
3639 exception = e;
|
|
3640 }
|
|
3641
|
|
3642 this.restore();
|
|
3643
|
|
3644 if (exception) {
|
|
3645 throw exception;
|
|
3646 }
|
|
3647 },
|
|
3648
|
|
3649 add: function add(fake) {
|
|
3650 push.call(getFakes(this), fake);
|
|
3651 return fake;
|
|
3652 },
|
|
3653
|
|
3654 spy: function spy() {
|
|
3655 return this.add(sinon.spy.apply(sinon, arguments));
|
|
3656 },
|
|
3657
|
|
3658 stub: function stub(object, property, value) {
|
|
3659 if (property) {
|
|
3660 var original = object[property];
|
|
3661
|
|
3662 if (typeof original != "function") {
|
|
3663 if (!hasOwnProperty.call(object, property)) {
|
|
3664 throw new TypeError("Cannot stub non-existent own property " + property);
|
|
3665 }
|
|
3666
|
|
3667 object[property] = value;
|
|
3668
|
|
3669 return this.add({
|
|
3670 restore: function () {
|
|
3671 object[property] = original;
|
|
3672 }
|
|
3673 });
|
|
3674 }
|
|
3675 }
|
|
3676 if (!property && !!object && typeof object == "object") {
|
|
3677 var stubbedObj = sinon.stub.apply(sinon, arguments);
|
|
3678
|
|
3679 for (var prop in stubbedObj) {
|
|
3680 if (typeof stubbedObj[prop] === "function") {
|
|
3681 this.add(stubbedObj[prop]);
|
|
3682 }
|
|
3683 }
|
|
3684
|
|
3685 return stubbedObj;
|
|
3686 }
|
|
3687
|
|
3688 return this.add(sinon.stub.apply(sinon, arguments));
|
|
3689 },
|
|
3690
|
|
3691 mock: function mock() {
|
|
3692 return this.add(sinon.mock.apply(sinon, arguments));
|
|
3693 },
|
|
3694
|
|
3695 inject: function inject(obj) {
|
|
3696 var col = this;
|
|
3697
|
|
3698 obj.spy = function () {
|
|
3699 return col.spy.apply(col, arguments);
|
|
3700 };
|
|
3701
|
|
3702 obj.stub = function () {
|
|
3703 return col.stub.apply(col, arguments);
|
|
3704 };
|
|
3705
|
|
3706 obj.mock = function () {
|
|
3707 return col.mock.apply(col, arguments);
|
|
3708 };
|
|
3709
|
|
3710 return obj;
|
|
3711 }
|
|
3712 };
|
|
3713
|
|
3714 sinon.collection = collection;
|
|
3715 return collection;
|
|
3716 }
|
|
3717
|
|
3718 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3719 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3720
|
|
3721 function loadDependencies(require, exports, module) {
|
|
3722 var sinon = require("./util/core");
|
|
3723 require("./mock");
|
|
3724 require("./spy");
|
|
3725 require("./stub");
|
|
3726 module.exports = makeApi(sinon);
|
|
3727 }
|
|
3728
|
|
3729 if (isAMD) {
|
|
3730 define(loadDependencies);
|
|
3731 } else if (isNode) {
|
|
3732 loadDependencies(require, module.exports, module);
|
|
3733 } else if (!sinon) {
|
|
3734 return;
|
|
3735 } else {
|
|
3736 makeApi(sinon);
|
|
3737 }
|
|
3738 }(typeof sinon == "object" && sinon || null));
|
|
3739
|
|
3740 /*global lolex */
|
|
3741
|
|
3742 /**
|
|
3743 * Fake timer API
|
|
3744 * setTimeout
|
|
3745 * setInterval
|
|
3746 * clearTimeout
|
|
3747 * clearInterval
|
|
3748 * tick
|
|
3749 * reset
|
|
3750 * Date
|
|
3751 *
|
|
3752 * Inspired by jsUnitMockTimeOut from JsUnit
|
|
3753 *
|
|
3754 * @author Christian Johansen ([email protected])
|
|
3755 * @license BSD
|
|
3756 *
|
|
3757 * Copyright (c) 2010-2013 Christian Johansen
|
|
3758 */
|
|
3759
|
|
3760 if (typeof sinon == "undefined") {
|
|
3761 var sinon = {};
|
|
3762 }
|
|
3763
|
|
3764 (function (global) {
|
|
3765 function makeApi(sinon, lol) {
|
|
3766 var _lolex = typeof lolex !== "undefined" ? lolex : lol;
|
|
3767
|
|
3768 sinon.useFakeTimers = function () {
|
|
3769 var now, methods = Array.prototype.slice.call(arguments);
|
|
3770
|
|
3771 if (typeof methods[0] === "string") {
|
|
3772 now = 0;
|
|
3773 } else {
|
|
3774 now = methods.shift();
|
|
3775 }
|
|
3776
|
|
3777 var clock = _lolex.install(now || 0, methods);
|
|
3778 clock.restore = clock.uninstall;
|
|
3779 return clock;
|
|
3780 };
|
|
3781
|
|
3782 sinon.clock = {
|
|
3783 create: function (now) {
|
|
3784 return _lolex.createClock(now);
|
|
3785 }
|
|
3786 };
|
|
3787
|
|
3788 sinon.timers = {
|
|
3789 setTimeout: setTimeout,
|
|
3790 clearTimeout: clearTimeout,
|
|
3791 setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
|
|
3792 clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined),
|
|
3793 setInterval: setInterval,
|
|
3794 clearInterval: clearInterval,
|
|
3795 Date: Date
|
|
3796 };
|
|
3797 }
|
|
3798
|
|
3799 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3800 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3801
|
|
3802 function loadDependencies(require, epxorts, module) {
|
|
3803 var sinon = require("./core");
|
|
3804 makeApi(sinon, require("lolex"));
|
|
3805 module.exports = sinon;
|
|
3806 }
|
|
3807
|
|
3808 if (isAMD) {
|
|
3809 define(loadDependencies);
|
|
3810 } else if (isNode) {
|
|
3811 loadDependencies(require, module.exports, module);
|
|
3812 } else {
|
|
3813 makeApi(sinon);
|
|
3814 }
|
|
3815 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
|
|
3816
|
|
3817 /**
|
|
3818 * Minimal Event interface implementation
|
|
3819 *
|
|
3820 * Original implementation by Sven Fuchs: https://gist.github.com/995028
|
|
3821 * Modifications and tests by Christian Johansen.
|
|
3822 *
|
|
3823 * @author Sven Fuchs ([email protected])
|
|
3824 * @author Christian Johansen ([email protected])
|
|
3825 * @license BSD
|
|
3826 *
|
|
3827 * Copyright (c) 2011 Sven Fuchs, Christian Johansen
|
|
3828 */
|
|
3829
|
|
3830 if (typeof sinon == "undefined") {
|
|
3831 this.sinon = {};
|
|
3832 }
|
|
3833
|
|
3834 (function () {
|
|
3835 var push = [].push;
|
|
3836
|
|
3837 function makeApi(sinon) {
|
|
3838 sinon.Event = function Event(type, bubbles, cancelable, target) {
|
|
3839 this.initEvent(type, bubbles, cancelable, target);
|
|
3840 };
|
|
3841
|
|
3842 sinon.Event.prototype = {
|
|
3843 initEvent: function (type, bubbles, cancelable, target) {
|
|
3844 this.type = type;
|
|
3845 this.bubbles = bubbles;
|
|
3846 this.cancelable = cancelable;
|
|
3847 this.target = target;
|
|
3848 },
|
|
3849
|
|
3850 stopPropagation: function () {},
|
|
3851
|
|
3852 preventDefault: function () {
|
|
3853 this.defaultPrevented = true;
|
|
3854 }
|
|
3855 };
|
|
3856
|
|
3857 sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
|
|
3858 this.initEvent(type, false, false, target);
|
|
3859 this.loaded = progressEventRaw.loaded || null;
|
|
3860 this.total = progressEventRaw.total || null;
|
|
3861 };
|
|
3862
|
|
3863 sinon.ProgressEvent.prototype = new sinon.Event();
|
|
3864
|
|
3865 sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
|
|
3866
|
|
3867 sinon.CustomEvent = function CustomEvent(type, customData, target) {
|
|
3868 this.initEvent(type, false, false, target);
|
|
3869 this.detail = customData.detail || null;
|
|
3870 };
|
|
3871
|
|
3872 sinon.CustomEvent.prototype = new sinon.Event();
|
|
3873
|
|
3874 sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
|
|
3875
|
|
3876 sinon.EventTarget = {
|
|
3877 addEventListener: function addEventListener(event, listener) {
|
|
3878 this.eventListeners = this.eventListeners || {};
|
|
3879 this.eventListeners[event] = this.eventListeners[event] || [];
|
|
3880 push.call(this.eventListeners[event], listener);
|
|
3881 },
|
|
3882
|
|
3883 removeEventListener: function removeEventListener(event, listener) {
|
|
3884 var listeners = this.eventListeners && this.eventListeners[event] || [];
|
|
3885
|
|
3886 for (var i = 0, l = listeners.length; i < l; ++i) {
|
|
3887 if (listeners[i] == listener) {
|
|
3888 return listeners.splice(i, 1);
|
|
3889 }
|
|
3890 }
|
|
3891 },
|
|
3892
|
|
3893 dispatchEvent: function dispatchEvent(event) {
|
|
3894 var type = event.type;
|
|
3895 var listeners = this.eventListeners && this.eventListeners[type] || [];
|
|
3896
|
|
3897 for (var i = 0; i < listeners.length; i++) {
|
|
3898 if (typeof listeners[i] == "function") {
|
|
3899 listeners[i].call(this, event);
|
|
3900 } else {
|
|
3901 listeners[i].handleEvent(event);
|
|
3902 }
|
|
3903 }
|
|
3904
|
|
3905 return !!event.defaultPrevented;
|
|
3906 }
|
|
3907 };
|
|
3908 }
|
|
3909
|
|
3910 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3911 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3912
|
|
3913 function loadDependencies(require) {
|
|
3914 var sinon = require("./core");
|
|
3915 makeApi(sinon);
|
|
3916 }
|
|
3917
|
|
3918 if (isAMD) {
|
|
3919 define(loadDependencies);
|
|
3920 } else if (isNode) {
|
|
3921 loadDependencies(require);
|
|
3922 } else {
|
|
3923 makeApi(sinon);
|
|
3924 }
|
|
3925 }());
|
|
3926
|
|
3927 /**
|
|
3928 * @depend ../sinon.js
|
|
3929 */
|
|
3930 /**
|
|
3931 * Logs errors
|
|
3932 *
|
|
3933 * @author Christian Johansen ([email protected])
|
|
3934 * @license BSD
|
|
3935 *
|
|
3936 * Copyright (c) 2010-2014 Christian Johansen
|
|
3937 */
|
|
3938
|
|
3939 (function (sinon) {
|
|
3940 // cache a reference to setTimeout, so that our reference won't be stubbed out
|
|
3941 // when using fake timers and errors will still get logged
|
|
3942 // https://github.com/cjohansen/Sinon.JS/issues/381
|
|
3943 var realSetTimeout = setTimeout;
|
|
3944
|
|
3945 function makeApi(sinon) {
|
|
3946
|
|
3947 function log() {}
|
|
3948
|
|
3949 function logError(label, err) {
|
|
3950 var msg = label + " threw exception: ";
|
|
3951
|
|
3952 sinon.log(msg + "[" + err.name + "] " + err.message);
|
|
3953
|
|
3954 if (err.stack) {
|
|
3955 sinon.log(err.stack);
|
|
3956 }
|
|
3957
|
|
3958 logError.setTimeout(function () {
|
|
3959 err.message = msg + err.message;
|
|
3960 throw err;
|
|
3961 }, 0);
|
|
3962 };
|
|
3963
|
|
3964 // wrap realSetTimeout with something we can stub in tests
|
|
3965 logError.setTimeout = function (func, timeout) {
|
|
3966 realSetTimeout(func, timeout);
|
|
3967 }
|
|
3968
|
|
3969 var exports = {};
|
|
3970 exports.log = sinon.log = log;
|
|
3971 exports.logError = sinon.logError = logError;
|
|
3972
|
|
3973 return exports;
|
|
3974 }
|
|
3975
|
|
3976 function loadDependencies(require, exports, module) {
|
|
3977 var sinon = require("./util/core");
|
|
3978 module.exports = makeApi(sinon);
|
|
3979 }
|
|
3980
|
|
3981 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
3982 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
3983
|
|
3984 if (isAMD) {
|
|
3985 define(loadDependencies);
|
|
3986 } else if (isNode) {
|
|
3987 loadDependencies(require, module.exports, module);
|
|
3988 } else if (!sinon) {
|
|
3989 return;
|
|
3990 } else {
|
|
3991 makeApi(sinon);
|
|
3992 }
|
|
3993 }(typeof sinon == "object" && sinon || null));
|
|
3994
|
|
3995 /**
|
|
3996 * @depend core.js
|
|
3997 * @depend ../extend.js
|
|
3998 * @depend event.js
|
|
3999 * @depend ../log_error.js
|
|
4000 */
|
|
4001 /**
|
|
4002 * Fake XMLHttpRequest object
|
|
4003 *
|
|
4004 * @author Christian Johansen ([email protected])
|
|
4005 * @license BSD
|
|
4006 *
|
|
4007 * Copyright (c) 2010-2013 Christian Johansen
|
|
4008 */
|
|
4009
|
|
4010 (function (global) {
|
|
4011
|
|
4012 var supportsProgress = typeof ProgressEvent !== "undefined";
|
|
4013 var supportsCustomEvent = typeof CustomEvent !== "undefined";
|
|
4014 var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest };
|
|
4015 sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
|
|
4016 sinonXhr.GlobalActiveXObject = global.ActiveXObject;
|
|
4017 sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined";
|
|
4018 sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined";
|
|
4019 sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX
|
|
4020 ? function () { return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
|
|
4021 sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest());
|
|
4022
|
|
4023 /*jsl:ignore*/
|
|
4024 var unsafeHeaders = {
|
|
4025 "Accept-Charset": true,
|
|
4026 "Accept-Encoding": true,
|
|
4027 Connection: true,
|
|
4028 "Content-Length": true,
|
|
4029 Cookie: true,
|
|
4030 Cookie2: true,
|
|
4031 "Content-Transfer-Encoding": true,
|
|
4032 Date: true,
|
|
4033 Expect: true,
|
|
4034 Host: true,
|
|
4035 "Keep-Alive": true,
|
|
4036 Referer: true,
|
|
4037 TE: true,
|
|
4038 Trailer: true,
|
|
4039 "Transfer-Encoding": true,
|
|
4040 Upgrade: true,
|
|
4041 "User-Agent": true,
|
|
4042 Via: true
|
|
4043 };
|
|
4044 /*jsl:end*/
|
|
4045
|
|
4046 function FakeXMLHttpRequest() {
|
|
4047 this.readyState = FakeXMLHttpRequest.UNSENT;
|
|
4048 this.requestHeaders = {};
|
|
4049 this.requestBody = null;
|
|
4050 this.status = 0;
|
|
4051 this.statusText = "";
|
|
4052 this.upload = new UploadProgress();
|
|
4053 if (sinonXhr.supportsCORS) {
|
|
4054 this.withCredentials = false;
|
|
4055 }
|
|
4056
|
|
4057 var xhr = this;
|
|
4058 var events = ["loadstart", "load", "abort", "loadend"];
|
|
4059
|
|
4060 function addEventListener(eventName) {
|
|
4061 xhr.addEventListener(eventName, function (event) {
|
|
4062 var listener = xhr["on" + eventName];
|
|
4063
|
|
4064 if (listener && typeof listener == "function") {
|
|
4065 listener.call(this, event);
|
|
4066 }
|
|
4067 });
|
|
4068 }
|
|
4069
|
|
4070 for (var i = events.length - 1; i >= 0; i--) {
|
|
4071 addEventListener(events[i]);
|
|
4072 }
|
|
4073
|
|
4074 if (typeof FakeXMLHttpRequest.onCreate == "function") {
|
|
4075 FakeXMLHttpRequest.onCreate(this);
|
|
4076 }
|
|
4077 }
|
|
4078
|
|
4079 // An upload object is created for each
|
|
4080 // FakeXMLHttpRequest and allows upload
|
|
4081 // events to be simulated using uploadProgress
|
|
4082 // and uploadError.
|
|
4083 function UploadProgress() {
|
|
4084 this.eventListeners = {
|
|
4085 progress: [],
|
|
4086 load: [],
|
|
4087 abort: [],
|
|
4088 error: []
|
|
4089 }
|
|
4090 }
|
|
4091
|
|
4092 UploadProgress.prototype.addEventListener = function addEventListener(event, listener) {
|
|
4093 this.eventListeners[event].push(listener);
|
|
4094 };
|
|
4095
|
|
4096 UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) {
|
|
4097 var listeners = this.eventListeners[event] || [];
|
|
4098
|
|
4099 for (var i = 0, l = listeners.length; i < l; ++i) {
|
|
4100 if (listeners[i] == listener) {
|
|
4101 return listeners.splice(i, 1);
|
|
4102 }
|
|
4103 }
|
|
4104 };
|
|
4105
|
|
4106 UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) {
|
|
4107 var listeners = this.eventListeners[event.type] || [];
|
|
4108
|
|
4109 for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
|
|
4110 listener(event);
|
|
4111 }
|
|
4112 };
|
|
4113
|
|
4114 function verifyState(xhr) {
|
|
4115 if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
|
|
4116 throw new Error("INVALID_STATE_ERR");
|
|
4117 }
|
|
4118
|
|
4119 if (xhr.sendFlag) {
|
|
4120 throw new Error("INVALID_STATE_ERR");
|
|
4121 }
|
|
4122 }
|
|
4123
|
|
4124 function getHeader(headers, header) {
|
|
4125 header = header.toLowerCase();
|
|
4126
|
|
4127 for (var h in headers) {
|
|
4128 if (h.toLowerCase() == header) {
|
|
4129 return h;
|
|
4130 }
|
|
4131 }
|
|
4132
|
|
4133 return null;
|
|
4134 }
|
|
4135
|
|
4136 // filtering to enable a white-list version of Sinon FakeXhr,
|
|
4137 // where whitelisted requests are passed through to real XHR
|
|
4138 function each(collection, callback) {
|
|
4139 if (!collection) {
|
|
4140 return;
|
|
4141 }
|
|
4142
|
|
4143 for (var i = 0, l = collection.length; i < l; i += 1) {
|
|
4144 callback(collection[i]);
|
|
4145 }
|
|
4146 }
|
|
4147 function some(collection, callback) {
|
|
4148 for (var index = 0; index < collection.length; index++) {
|
|
4149 if (callback(collection[index]) === true) {
|
|
4150 return true;
|
|
4151 }
|
|
4152 }
|
|
4153 return false;
|
|
4154 }
|
|
4155 // largest arity in XHR is 5 - XHR#open
|
|
4156 var apply = function (obj, method, args) {
|
|
4157 switch (args.length) {
|
|
4158 case 0: return obj[method]();
|
|
4159 case 1: return obj[method](args[0]);
|
|
4160 case 2: return obj[method](args[0], args[1]);
|
|
4161 case 3: return obj[method](args[0], args[1], args[2]);
|
|
4162 case 4: return obj[method](args[0], args[1], args[2], args[3]);
|
|
4163 case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]);
|
|
4164 }
|
|
4165 };
|
|
4166
|
|
4167 FakeXMLHttpRequest.filters = [];
|
|
4168 FakeXMLHttpRequest.addFilter = function addFilter(fn) {
|
|
4169 this.filters.push(fn)
|
|
4170 };
|
|
4171 var IE6Re = /MSIE 6/;
|
|
4172 FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {
|
|
4173 var xhr = new sinonXhr.workingXHR();
|
|
4174 each([
|
|
4175 "open",
|
|
4176 "setRequestHeader",
|
|
4177 "send",
|
|
4178 "abort",
|
|
4179 "getResponseHeader",
|
|
4180 "getAllResponseHeaders",
|
|
4181 "addEventListener",
|
|
4182 "overrideMimeType",
|
|
4183 "removeEventListener"
|
|
4184 ], function (method) {
|
|
4185 fakeXhr[method] = function () {
|
|
4186 return apply(xhr, method, arguments);
|
|
4187 };
|
|
4188 });
|
|
4189
|
|
4190 var copyAttrs = function (args) {
|
|
4191 each(args, function (attr) {
|
|
4192 try {
|
|
4193 fakeXhr[attr] = xhr[attr]
|
|
4194 } catch (e) {
|
|
4195 if (!IE6Re.test(navigator.userAgent)) {
|
|
4196 throw e;
|
|
4197 }
|
|
4198 }
|
|
4199 });
|
|
4200 };
|
|
4201
|
|
4202 var stateChange = function stateChange() {
|
|
4203 fakeXhr.readyState = xhr.readyState;
|
|
4204 if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
|
|
4205 copyAttrs(["status", "statusText"]);
|
|
4206 }
|
|
4207 if (xhr.readyState >= FakeXMLHttpRequest.LOADING) {
|
|
4208 copyAttrs(["responseText", "response"]);
|
|
4209 }
|
|
4210 if (xhr.readyState === FakeXMLHttpRequest.DONE) {
|
|
4211 copyAttrs(["responseXML"]);
|
|
4212 }
|
|
4213 if (fakeXhr.onreadystatechange) {
|
|
4214 fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
|
|
4215 }
|
|
4216 };
|
|
4217
|
|
4218 if (xhr.addEventListener) {
|
|
4219 for (var event in fakeXhr.eventListeners) {
|
|
4220 if (fakeXhr.eventListeners.hasOwnProperty(event)) {
|
|
4221 each(fakeXhr.eventListeners[event], function (handler) {
|
|
4222 xhr.addEventListener(event, handler);
|
|
4223 });
|
|
4224 }
|
|
4225 }
|
|
4226 xhr.addEventListener("readystatechange", stateChange);
|
|
4227 } else {
|
|
4228 xhr.onreadystatechange = stateChange;
|
|
4229 }
|
|
4230 apply(xhr, "open", xhrArgs);
|
|
4231 };
|
|
4232 FakeXMLHttpRequest.useFilters = false;
|
|
4233
|
|
4234 function verifyRequestOpened(xhr) {
|
|
4235 if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
|
|
4236 throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
|
|
4237 }
|
|
4238 }
|
|
4239
|
|
4240 function verifyRequestSent(xhr) {
|
|
4241 if (xhr.readyState == FakeXMLHttpRequest.DONE) {
|
|
4242 throw new Error("Request done");
|
|
4243 }
|
|
4244 }
|
|
4245
|
|
4246 function verifyHeadersReceived(xhr) {
|
|
4247 if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
|
|
4248 throw new Error("No headers received");
|
|
4249 }
|
|
4250 }
|
|
4251
|
|
4252 function verifyResponseBodyType(body) {
|
|
4253 if (typeof body != "string") {
|
|
4254 var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
|
|
4255 body + ", which is not a string.");
|
|
4256 error.name = "InvalidBodyException";
|
|
4257 throw error;
|
|
4258 }
|
|
4259 }
|
|
4260
|
|
4261 FakeXMLHttpRequest.parseXML = function parseXML(text) {
|
|
4262 var xmlDoc;
|
|
4263
|
|
4264 if (typeof DOMParser != "undefined") {
|
|
4265 var parser = new DOMParser();
|
|
4266 xmlDoc = parser.parseFromString(text, "text/xml");
|
|
4267 } else {
|
|
4268 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
|
|
4269 xmlDoc.async = "false";
|
|
4270 xmlDoc.loadXML(text);
|
|
4271 }
|
|
4272
|
|
4273 return xmlDoc;
|
|
4274 };
|
|
4275
|
|
4276 FakeXMLHttpRequest.statusCodes = {
|
|
4277 100: "Continue",
|
|
4278 101: "Switching Protocols",
|
|
4279 200: "OK",
|
|
4280 201: "Created",
|
|
4281 202: "Accepted",
|
|
4282 203: "Non-Authoritative Information",
|
|
4283 204: "No Content",
|
|
4284 205: "Reset Content",
|
|
4285 206: "Partial Content",
|
|
4286 300: "Multiple Choice",
|
|
4287 301: "Moved Permanently",
|
|
4288 302: "Found",
|
|
4289 303: "See Other",
|
|
4290 304: "Not Modified",
|
|
4291 305: "Use Proxy",
|
|
4292 307: "Temporary Redirect",
|
|
4293 400: "Bad Request",
|
|
4294 401: "Unauthorized",
|
|
4295 402: "Payment Required",
|
|
4296 403: "Forbidden",
|
|
4297 404: "Not Found",
|
|
4298 405: "Method Not Allowed",
|
|
4299 406: "Not Acceptable",
|
|
4300 407: "Proxy Authentication Required",
|
|
4301 408: "Request Timeout",
|
|
4302 409: "Conflict",
|
|
4303 410: "Gone",
|
|
4304 411: "Length Required",
|
|
4305 412: "Precondition Failed",
|
|
4306 413: "Request Entity Too Large",
|
|
4307 414: "Request-URI Too Long",
|
|
4308 415: "Unsupported Media Type",
|
|
4309 416: "Requested Range Not Satisfiable",
|
|
4310 417: "Expectation Failed",
|
|
4311 422: "Unprocessable Entity",
|
|
4312 500: "Internal Server Error",
|
|
4313 501: "Not Implemented",
|
|
4314 502: "Bad Gateway",
|
|
4315 503: "Service Unavailable",
|
|
4316 504: "Gateway Timeout",
|
|
4317 505: "HTTP Version Not Supported"
|
|
4318 };
|
|
4319
|
|
4320 function makeApi(sinon) {
|
|
4321 sinon.xhr = sinonXhr;
|
|
4322
|
|
4323 sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
|
|
4324 async: true,
|
|
4325
|
|
4326 open: function open(method, url, async, username, password) {
|
|
4327 this.method = method;
|
|
4328 this.url = url;
|
|
4329 this.async = typeof async == "boolean" ? async : true;
|
|
4330 this.username = username;
|
|
4331 this.password = password;
|
|
4332 this.responseText = null;
|
|
4333 this.responseXML = null;
|
|
4334 this.requestHeaders = {};
|
|
4335 this.sendFlag = false;
|
|
4336
|
|
4337 if (FakeXMLHttpRequest.useFilters === true) {
|
|
4338 var xhrArgs = arguments;
|
|
4339 var defake = some(FakeXMLHttpRequest.filters, function (filter) {
|
|
4340 return filter.apply(this, xhrArgs)
|
|
4341 });
|
|
4342 if (defake) {
|
|
4343 return FakeXMLHttpRequest.defake(this, arguments);
|
|
4344 }
|
|
4345 }
|
|
4346 this.readyStateChange(FakeXMLHttpRequest.OPENED);
|
|
4347 },
|
|
4348
|
|
4349 readyStateChange: function readyStateChange(state) {
|
|
4350 this.readyState = state;
|
|
4351
|
|
4352 if (typeof this.onreadystatechange == "function") {
|
|
4353 try {
|
|
4354 this.onreadystatechange();
|
|
4355 } catch (e) {
|
|
4356 sinon.logError("Fake XHR onreadystatechange handler", e);
|
|
4357 }
|
|
4358 }
|
|
4359
|
|
4360 this.dispatchEvent(new sinon.Event("readystatechange"));
|
|
4361
|
|
4362 switch (this.readyState) {
|
|
4363 case FakeXMLHttpRequest.DONE:
|
|
4364 this.dispatchEvent(new sinon.Event("load", false, false, this));
|
|
4365 this.dispatchEvent(new sinon.Event("loadend", false, false, this));
|
|
4366 this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
|
|
4367 if (supportsProgress) {
|
|
4368 this.upload.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100}));
|
|
4369 }
|
|
4370 break;
|
|
4371 }
|
|
4372 },
|
|
4373
|
|
4374 setRequestHeader: function setRequestHeader(header, value) {
|
|
4375 verifyState(this);
|
|
4376
|
|
4377 if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
|
|
4378 throw new Error("Refused to set unsafe header \"" + header + "\"");
|
|
4379 }
|
|
4380
|
|
4381 if (this.requestHeaders[header]) {
|
|
4382 this.requestHeaders[header] += "," + value;
|
|
4383 } else {
|
|
4384 this.requestHeaders[header] = value;
|
|
4385 }
|
|
4386 },
|
|
4387
|
|
4388 // Helps testing
|
|
4389 setResponseHeaders: function setResponseHeaders(headers) {
|
|
4390 verifyRequestOpened(this);
|
|
4391 this.responseHeaders = {};
|
|
4392
|
|
4393 for (var header in headers) {
|
|
4394 if (headers.hasOwnProperty(header)) {
|
|
4395 this.responseHeaders[header] = headers[header];
|
|
4396 }
|
|
4397 }
|
|
4398
|
|
4399 if (this.async) {
|
|
4400 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
|
|
4401 } else {
|
|
4402 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
|
|
4403 }
|
|
4404 },
|
|
4405
|
|
4406 // Currently treats ALL data as a DOMString (i.e. no Document)
|
|
4407 send: function send(data) {
|
|
4408 verifyState(this);
|
|
4409
|
|
4410 if (!/^(get|head)$/i.test(this.method)) {
|
|
4411 var contentType = getHeader(this.requestHeaders, "Content-Type");
|
|
4412 if (this.requestHeaders[contentType]) {
|
|
4413 var value = this.requestHeaders[contentType].split(";");
|
|
4414 this.requestHeaders[contentType] = value[0] + ";charset=utf-8";
|
|
4415 } else {
|
|
4416 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
|
|
4417 }
|
|
4418
|
|
4419 this.requestBody = data;
|
|
4420 }
|
|
4421
|
|
4422 this.errorFlag = false;
|
|
4423 this.sendFlag = this.async;
|
|
4424 this.readyStateChange(FakeXMLHttpRequest.OPENED);
|
|
4425
|
|
4426 if (typeof this.onSend == "function") {
|
|
4427 this.onSend(this);
|
|
4428 }
|
|
4429
|
|
4430 this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
|
|
4431 },
|
|
4432
|
|
4433 abort: function abort() {
|
|
4434 this.aborted = true;
|
|
4435 this.responseText = null;
|
|
4436 this.errorFlag = true;
|
|
4437 this.requestHeaders = {};
|
|
4438
|
|
4439 if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) {
|
|
4440 this.readyStateChange(FakeXMLHttpRequest.DONE);
|
|
4441 this.sendFlag = false;
|
|
4442 }
|
|
4443
|
|
4444 this.readyState = FakeXMLHttpRequest.UNSENT;
|
|
4445
|
|
4446 this.dispatchEvent(new sinon.Event("abort", false, false, this));
|
|
4447
|
|
4448 this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
|
|
4449
|
|
4450 if (typeof this.onerror === "function") {
|
|
4451 this.onerror();
|
|
4452 }
|
|
4453 },
|
|
4454
|
|
4455 getResponseHeader: function getResponseHeader(header) {
|
|
4456 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
|
|
4457 return null;
|
|
4458 }
|
|
4459
|
|
4460 if (/^Set-Cookie2?$/i.test(header)) {
|
|
4461 return null;
|
|
4462 }
|
|
4463
|
|
4464 header = getHeader(this.responseHeaders, header);
|
|
4465
|
|
4466 return this.responseHeaders[header] || null;
|
|
4467 },
|
|
4468
|
|
4469 getAllResponseHeaders: function getAllResponseHeaders() {
|
|
4470 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
|
|
4471 return "";
|
|
4472 }
|
|
4473
|
|
4474 var headers = "";
|
|
4475
|
|
4476 for (var header in this.responseHeaders) {
|
|
4477 if (this.responseHeaders.hasOwnProperty(header) &&
|
|
4478 !/^Set-Cookie2?$/i.test(header)) {
|
|
4479 headers += header + ": " + this.responseHeaders[header] + "\r\n";
|
|
4480 }
|
|
4481 }
|
|
4482
|
|
4483 return headers;
|
|
4484 },
|
|
4485
|
|
4486 setResponseBody: function setResponseBody(body) {
|
|
4487 verifyRequestSent(this);
|
|
4488 verifyHeadersReceived(this);
|
|
4489 verifyResponseBodyType(body);
|
|
4490
|
|
4491 var chunkSize = this.chunkSize || 10;
|
|
4492 var index = 0;
|
|
4493 this.responseText = "";
|
|
4494
|
|
4495 do {
|
|
4496 if (this.async) {
|
|
4497 this.readyStateChange(FakeXMLHttpRequest.LOADING);
|
|
4498 }
|
|
4499
|
|
4500 this.responseText += body.substring(index, index + chunkSize);
|
|
4501 index += chunkSize;
|
|
4502 } while (index < body.length);
|
|
4503
|
|
4504 var type = this.getResponseHeader("Content-Type");
|
|
4505
|
|
4506 if (this.responseText &&
|
|
4507 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
|
|
4508 try {
|
|
4509 this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
|
|
4510 } catch (e) {
|
|
4511 // Unable to parse XML - no biggie
|
|
4512 }
|
|
4513 }
|
|
4514
|
|
4515 this.readyStateChange(FakeXMLHttpRequest.DONE);
|
|
4516 },
|
|
4517
|
|
4518 respond: function respond(status, headers, body) {
|
|
4519 this.status = typeof status == "number" ? status : 200;
|
|
4520 this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
|
|
4521 this.setResponseHeaders(headers || {});
|
|
4522 this.setResponseBody(body || "");
|
|
4523 },
|
|
4524
|
|
4525 uploadProgress: function uploadProgress(progressEventRaw) {
|
|
4526 if (supportsProgress) {
|
|
4527 this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
|
|
4528 }
|
|
4529 },
|
|
4530
|
|
4531 uploadError: function uploadError(error) {
|
|
4532 if (supportsCustomEvent) {
|
|
4533 this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error}));
|
|
4534 }
|
|
4535 }
|
|
4536 });
|
|
4537
|
|
4538 sinon.extend(FakeXMLHttpRequest, {
|
|
4539 UNSENT: 0,
|
|
4540 OPENED: 1,
|
|
4541 HEADERS_RECEIVED: 2,
|
|
4542 LOADING: 3,
|
|
4543 DONE: 4
|
|
4544 });
|
|
4545
|
|
4546 sinon.useFakeXMLHttpRequest = function () {
|
|
4547 FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
|
|
4548 if (sinonXhr.supportsXHR) {
|
|
4549 global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest;
|
|
4550 }
|
|
4551
|
|
4552 if (sinonXhr.supportsActiveX) {
|
|
4553 global.ActiveXObject = sinonXhr.GlobalActiveXObject;
|
|
4554 }
|
|
4555
|
|
4556 delete FakeXMLHttpRequest.restore;
|
|
4557
|
|
4558 if (keepOnCreate !== true) {
|
|
4559 delete FakeXMLHttpRequest.onCreate;
|
|
4560 }
|
|
4561 };
|
|
4562 if (sinonXhr.supportsXHR) {
|
|
4563 global.XMLHttpRequest = FakeXMLHttpRequest;
|
|
4564 }
|
|
4565
|
|
4566 if (sinonXhr.supportsActiveX) {
|
|
4567 global.ActiveXObject = function ActiveXObject(objId) {
|
|
4568 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
|
|
4569
|
|
4570 return new FakeXMLHttpRequest();
|
|
4571 }
|
|
4572
|
|
4573 return new sinonXhr.GlobalActiveXObject(objId);
|
|
4574 };
|
|
4575 }
|
|
4576
|
|
4577 return FakeXMLHttpRequest;
|
|
4578 };
|
|
4579
|
|
4580 sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
|
|
4581 }
|
|
4582
|
|
4583 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
4584 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
4585
|
|
4586 function loadDependencies(require, exports, module) {
|
|
4587 var sinon = require("./core");
|
|
4588 require("./event");
|
|
4589 makeApi(sinon);
|
|
4590 module.exports = sinon;
|
|
4591 }
|
|
4592
|
|
4593 if (isAMD) {
|
|
4594 define(loadDependencies);
|
|
4595 } else if (isNode) {
|
|
4596 loadDependencies(require, module.exports, module);
|
|
4597 } else if (typeof sinon === "undefined") {
|
|
4598 return;
|
|
4599 } else {
|
|
4600 makeApi(sinon);
|
|
4601 }
|
|
4602
|
|
4603 })(typeof self !== "undefined" ? self : this);
|
|
4604
|
|
4605 /**
|
|
4606 * @depend fake_xml_http_request.js
|
|
4607 * @depend ../format.js
|
|
4608 * @depend ../log_error.js
|
|
4609 */
|
|
4610 /**
|
|
4611 * The Sinon "server" mimics a web server that receives requests from
|
|
4612 * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
|
|
4613 * both synchronously and asynchronously. To respond synchronuously, canned
|
|
4614 * answers have to be provided upfront.
|
|
4615 *
|
|
4616 * @author Christian Johansen ([email protected])
|
|
4617 * @license BSD
|
|
4618 *
|
|
4619 * Copyright (c) 2010-2013 Christian Johansen
|
|
4620 */
|
|
4621
|
|
4622 if (typeof sinon == "undefined") {
|
|
4623 var sinon = {};
|
|
4624 }
|
|
4625
|
|
4626 (function () {
|
|
4627 var push = [].push;
|
|
4628 function F() {}
|
|
4629
|
|
4630 function create(proto) {
|
|
4631 F.prototype = proto;
|
|
4632 return new F();
|
|
4633 }
|
|
4634
|
|
4635 function responseArray(handler) {
|
|
4636 var response = handler;
|
|
4637
|
|
4638 if (Object.prototype.toString.call(handler) != "[object Array]") {
|
|
4639 response = [200, {}, handler];
|
|
4640 }
|
|
4641
|
|
4642 if (typeof response[2] != "string") {
|
|
4643 throw new TypeError("Fake server response body should be string, but was " +
|
|
4644 typeof response[2]);
|
|
4645 }
|
|
4646
|
|
4647 return response;
|
|
4648 }
|
|
4649
|
|
4650 var wloc = typeof window !== "undefined" ? window.location : {};
|
|
4651 var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
|
|
4652
|
|
4653 function matchOne(response, reqMethod, reqUrl) {
|
|
4654 var rmeth = response.method;
|
|
4655 var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
|
|
4656 var url = response.url;
|
|
4657 var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
|
|
4658
|
|
4659 return matchMethod && matchUrl;
|
|
4660 }
|
|
4661
|
|
4662 function match(response, request) {
|
|
4663 var requestUrl = request.url;
|
|
4664
|
|
4665 if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
|
|
4666 requestUrl = requestUrl.replace(rCurrLoc, "");
|
|
4667 }
|
|
4668
|
|
4669 if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
|
|
4670 if (typeof response.response == "function") {
|
|
4671 var ru = response.url;
|
|
4672 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
|
|
4673 return response.response.apply(response, args);
|
|
4674 }
|
|
4675
|
|
4676 return true;
|
|
4677 }
|
|
4678
|
|
4679 return false;
|
|
4680 }
|
|
4681
|
|
4682 function makeApi(sinon) {
|
|
4683 sinon.fakeServer = {
|
|
4684 create: function () {
|
|
4685 var server = create(this);
|
|
4686 this.xhr = sinon.useFakeXMLHttpRequest();
|
|
4687 server.requests = [];
|
|
4688
|
|
4689 this.xhr.onCreate = function (xhrObj) {
|
|
4690 server.addRequest(xhrObj);
|
|
4691 };
|
|
4692
|
|
4693 return server;
|
|
4694 },
|
|
4695
|
|
4696 addRequest: function addRequest(xhrObj) {
|
|
4697 var server = this;
|
|
4698 push.call(this.requests, xhrObj);
|
|
4699
|
|
4700 xhrObj.onSend = function () {
|
|
4701 server.handleRequest(this);
|
|
4702
|
|
4703 if (server.autoRespond && !server.responding) {
|
|
4704 setTimeout(function () {
|
|
4705 server.responding = false;
|
|
4706 server.respond();
|
|
4707 }, server.autoRespondAfter || 10);
|
|
4708
|
|
4709 server.responding = true;
|
|
4710 }
|
|
4711 };
|
|
4712 },
|
|
4713
|
|
4714 getHTTPMethod: function getHTTPMethod(request) {
|
|
4715 if (this.fakeHTTPMethods && /post/i.test(request.method)) {
|
|
4716 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
|
|
4717 return !!matches ? matches[1] : request.method;
|
|
4718 }
|
|
4719
|
|
4720 return request.method;
|
|
4721 },
|
|
4722
|
|
4723 handleRequest: function handleRequest(xhr) {
|
|
4724 if (xhr.async) {
|
|
4725 if (!this.queue) {
|
|
4726 this.queue = [];
|
|
4727 }
|
|
4728
|
|
4729 push.call(this.queue, xhr);
|
|
4730 } else {
|
|
4731 this.processRequest(xhr);
|
|
4732 }
|
|
4733 },
|
|
4734
|
|
4735 log: function log(response, request) {
|
|
4736 var str;
|
|
4737
|
|
4738 str = "Request:\n" + sinon.format(request) + "\n\n";
|
|
4739 str += "Response:\n" + sinon.format(response) + "\n\n";
|
|
4740
|
|
4741 sinon.log(str);
|
|
4742 },
|
|
4743
|
|
4744 respondWith: function respondWith(method, url, body) {
|
|
4745 if (arguments.length == 1 && typeof method != "function") {
|
|
4746 this.response = responseArray(method);
|
|
4747 return;
|
|
4748 }
|
|
4749
|
|
4750 if (!this.responses) { this.responses = []; }
|
|
4751
|
|
4752 if (arguments.length == 1) {
|
|
4753 body = method;
|
|
4754 url = method = null;
|
|
4755 }
|
|
4756
|
|
4757 if (arguments.length == 2) {
|
|
4758 body = url;
|
|
4759 url = method;
|
|
4760 method = null;
|
|
4761 }
|
|
4762
|
|
4763 push.call(this.responses, {
|
|
4764 method: method,
|
|
4765 url: url,
|
|
4766 response: typeof body == "function" ? body : responseArray(body)
|
|
4767 });
|
|
4768 },
|
|
4769
|
|
4770 respond: function respond() {
|
|
4771 if (arguments.length > 0) {
|
|
4772 this.respondWith.apply(this, arguments);
|
|
4773 }
|
|
4774
|
|
4775 var queue = this.queue || [];
|
|
4776 var requests = queue.splice(0, queue.length);
|
|
4777 var request;
|
|
4778
|
|
4779 while (request = requests.shift()) {
|
|
4780 this.processRequest(request);
|
|
4781 }
|
|
4782 },
|
|
4783
|
|
4784 processRequest: function processRequest(request) {
|
|
4785 try {
|
|
4786 if (request.aborted) {
|
|
4787 return;
|
|
4788 }
|
|
4789
|
|
4790 var response = this.response || [404, {}, ""];
|
|
4791
|
|
4792 if (this.responses) {
|
|
4793 for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
|
|
4794 if (match.call(this, this.responses[i], request)) {
|
|
4795 response = this.responses[i].response;
|
|
4796 break;
|
|
4797 }
|
|
4798 }
|
|
4799 }
|
|
4800
|
|
4801 if (request.readyState != 4) {
|
|
4802 this.log(response, request);
|
|
4803
|
|
4804 request.respond(response[0], response[1], response[2]);
|
|
4805 }
|
|
4806 } catch (e) {
|
|
4807 sinon.logError("Fake server request processing", e);
|
|
4808 }
|
|
4809 },
|
|
4810
|
|
4811 restore: function restore() {
|
|
4812 return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
|
|
4813 }
|
|
4814 };
|
|
4815 }
|
|
4816
|
|
4817 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
4818 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
4819
|
|
4820 function loadDependencies(require, exports, module) {
|
|
4821 var sinon = require("./core");
|
|
4822 require("./fake_xml_http_request");
|
|
4823 makeApi(sinon);
|
|
4824 module.exports = sinon;
|
|
4825 }
|
|
4826
|
|
4827 if (isAMD) {
|
|
4828 define(loadDependencies);
|
|
4829 } else if (isNode) {
|
|
4830 loadDependencies(require, module.exports, module);
|
|
4831 } else {
|
|
4832 makeApi(sinon);
|
|
4833 }
|
|
4834 }());
|
|
4835
|
|
4836 /**
|
|
4837 * @depend fake_server.js
|
|
4838 * @depend fake_timers.js
|
|
4839 */
|
|
4840 /**
|
|
4841 * Add-on for sinon.fakeServer that automatically handles a fake timer along with
|
|
4842 * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
|
|
4843 * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
|
|
4844 * it polls the object for completion with setInterval. Dispite the direct
|
|
4845 * motivation, there is nothing jQuery-specific in this file, so it can be used
|
|
4846 * in any environment where the ajax implementation depends on setInterval or
|
|
4847 * setTimeout.
|
|
4848 *
|
|
4849 * @author Christian Johansen ([email protected])
|
|
4850 * @license BSD
|
|
4851 *
|
|
4852 * Copyright (c) 2010-2013 Christian Johansen
|
|
4853 */
|
|
4854
|
|
4855 (function () {
|
|
4856 function makeApi(sinon) {
|
|
4857 function Server() {}
|
|
4858 Server.prototype = sinon.fakeServer;
|
|
4859
|
|
4860 sinon.fakeServerWithClock = new Server();
|
|
4861
|
|
4862 sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
|
|
4863 if (xhr.async) {
|
|
4864 if (typeof setTimeout.clock == "object") {
|
|
4865 this.clock = setTimeout.clock;
|
|
4866 } else {
|
|
4867 this.clock = sinon.useFakeTimers();
|
|
4868 this.resetClock = true;
|
|
4869 }
|
|
4870
|
|
4871 if (!this.longestTimeout) {
|
|
4872 var clockSetTimeout = this.clock.setTimeout;
|
|
4873 var clockSetInterval = this.clock.setInterval;
|
|
4874 var server = this;
|
|
4875
|
|
4876 this.clock.setTimeout = function (fn, timeout) {
|
|
4877 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
|
|
4878
|
|
4879 return clockSetTimeout.apply(this, arguments);
|
|
4880 };
|
|
4881
|
|
4882 this.clock.setInterval = function (fn, timeout) {
|
|
4883 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
|
|
4884
|
|
4885 return clockSetInterval.apply(this, arguments);
|
|
4886 };
|
|
4887 }
|
|
4888 }
|
|
4889
|
|
4890 return sinon.fakeServer.addRequest.call(this, xhr);
|
|
4891 };
|
|
4892
|
|
4893 sinon.fakeServerWithClock.respond = function respond() {
|
|
4894 var returnVal = sinon.fakeServer.respond.apply(this, arguments);
|
|
4895
|
|
4896 if (this.clock) {
|
|
4897 this.clock.tick(this.longestTimeout || 0);
|
|
4898 this.longestTimeout = 0;
|
|
4899
|
|
4900 if (this.resetClock) {
|
|
4901 this.clock.restore();
|
|
4902 this.resetClock = false;
|
|
4903 }
|
|
4904 }
|
|
4905
|
|
4906 return returnVal;
|
|
4907 };
|
|
4908
|
|
4909 sinon.fakeServerWithClock.restore = function restore() {
|
|
4910 if (this.clock) {
|
|
4911 this.clock.restore();
|
|
4912 }
|
|
4913
|
|
4914 return sinon.fakeServer.restore.apply(this, arguments);
|
|
4915 };
|
|
4916 }
|
|
4917
|
|
4918 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
4919 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
4920
|
|
4921 function loadDependencies(require) {
|
|
4922 var sinon = require("./core");
|
|
4923 require("./fake_server");
|
|
4924 require("./fake_timers");
|
|
4925 makeApi(sinon);
|
|
4926 }
|
|
4927
|
|
4928 if (isAMD) {
|
|
4929 define(loadDependencies);
|
|
4930 } else if (isNode) {
|
|
4931 loadDependencies(require);
|
|
4932 } else {
|
|
4933 makeApi(sinon);
|
|
4934 }
|
|
4935 }());
|
|
4936
|
|
4937 /**
|
|
4938 * @depend util/core.js
|
|
4939 * @depend extend.js
|
|
4940 * @depend collection.js
|
|
4941 * @depend util/fake_timers.js
|
|
4942 * @depend util/fake_server_with_clock.js
|
|
4943 */
|
|
4944 /**
|
|
4945 * Manages fake collections as well as fake utilities such as Sinon's
|
|
4946 * timers and fake XHR implementation in one convenient object.
|
|
4947 *
|
|
4948 * @author Christian Johansen ([email protected])
|
|
4949 * @license BSD
|
|
4950 *
|
|
4951 * Copyright (c) 2010-2013 Christian Johansen
|
|
4952 */
|
|
4953
|
|
4954 (function () {
|
|
4955 function makeApi(sinon) {
|
|
4956 var push = [].push;
|
|
4957
|
|
4958 function exposeValue(sandbox, config, key, value) {
|
|
4959 if (!value) {
|
|
4960 return;
|
|
4961 }
|
|
4962
|
|
4963 if (config.injectInto && !(key in config.injectInto)) {
|
|
4964 config.injectInto[key] = value;
|
|
4965 sandbox.injectedKeys.push(key);
|
|
4966 } else {
|
|
4967 push.call(sandbox.args, value);
|
|
4968 }
|
|
4969 }
|
|
4970
|
|
4971 function prepareSandboxFromConfig(config) {
|
|
4972 var sandbox = sinon.create(sinon.sandbox);
|
|
4973
|
|
4974 if (config.useFakeServer) {
|
|
4975 if (typeof config.useFakeServer == "object") {
|
|
4976 sandbox.serverPrototype = config.useFakeServer;
|
|
4977 }
|
|
4978
|
|
4979 sandbox.useFakeServer();
|
|
4980 }
|
|
4981
|
|
4982 if (config.useFakeTimers) {
|
|
4983 if (typeof config.useFakeTimers == "object") {
|
|
4984 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
|
|
4985 } else {
|
|
4986 sandbox.useFakeTimers();
|
|
4987 }
|
|
4988 }
|
|
4989
|
|
4990 return sandbox;
|
|
4991 }
|
|
4992
|
|
4993 sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
|
|
4994 useFakeTimers: function useFakeTimers() {
|
|
4995 this.clock = sinon.useFakeTimers.apply(sinon, arguments);
|
|
4996
|
|
4997 return this.add(this.clock);
|
|
4998 },
|
|
4999
|
|
5000 serverPrototype: sinon.fakeServer,
|
|
5001
|
|
5002 useFakeServer: function useFakeServer() {
|
|
5003 var proto = this.serverPrototype || sinon.fakeServer;
|
|
5004
|
|
5005 if (!proto || !proto.create) {
|
|
5006 return null;
|
|
5007 }
|
|
5008
|
|
5009 this.server = proto.create();
|
|
5010 return this.add(this.server);
|
|
5011 },
|
|
5012
|
|
5013 inject: function (obj) {
|
|
5014 sinon.collection.inject.call(this, obj);
|
|
5015
|
|
5016 if (this.clock) {
|
|
5017 obj.clock = this.clock;
|
|
5018 }
|
|
5019
|
|
5020 if (this.server) {
|
|
5021 obj.server = this.server;
|
|
5022 obj.requests = this.server.requests;
|
|
5023 }
|
|
5024
|
|
5025 obj.match = sinon.match;
|
|
5026
|
|
5027 return obj;
|
|
5028 },
|
|
5029
|
|
5030 restore: function () {
|
|
5031 sinon.collection.restore.apply(this, arguments);
|
|
5032 this.restoreContext();
|
|
5033 },
|
|
5034
|
|
5035 restoreContext: function () {
|
|
5036 if (this.injectedKeys) {
|
|
5037 for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
|
|
5038 delete this.injectInto[this.injectedKeys[i]];
|
|
5039 }
|
|
5040 this.injectedKeys = [];
|
|
5041 }
|
|
5042 },
|
|
5043
|
|
5044 create: function (config) {
|
|
5045 if (!config) {
|
|
5046 return sinon.create(sinon.sandbox);
|
|
5047 }
|
|
5048
|
|
5049 var sandbox = prepareSandboxFromConfig(config);
|
|
5050 sandbox.args = sandbox.args || [];
|
|
5051 sandbox.injectedKeys = [];
|
|
5052 sandbox.injectInto = config.injectInto;
|
|
5053 var prop, value, exposed = sandbox.inject({});
|
|
5054
|
|
5055 if (config.properties) {
|
|
5056 for (var i = 0, l = config.properties.length; i < l; i++) {
|
|
5057 prop = config.properties[i];
|
|
5058 value = exposed[prop] || prop == "sandbox" && sandbox;
|
|
5059 exposeValue(sandbox, config, prop, value);
|
|
5060 }
|
|
5061 } else {
|
|
5062 exposeValue(sandbox, config, "sandbox", value);
|
|
5063 }
|
|
5064
|
|
5065 return sandbox;
|
|
5066 },
|
|
5067
|
|
5068 match: sinon.match
|
|
5069 });
|
|
5070
|
|
5071 sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
|
|
5072
|
|
5073 return sinon.sandbox;
|
|
5074 }
|
|
5075
|
|
5076 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
5077 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
5078
|
|
5079 function loadDependencies(require, exports, module) {
|
|
5080 var sinon = require("./util/core");
|
|
5081 require("./util/fake_server");
|
|
5082 require("./util/fake_timers");
|
|
5083 require("./collection");
|
|
5084 module.exports = makeApi(sinon);
|
|
5085 }
|
|
5086
|
|
5087 if (isAMD) {
|
|
5088 define(loadDependencies);
|
|
5089 } else if (isNode) {
|
|
5090 loadDependencies(require, module.exports, module);
|
|
5091 } else if (!sinon) {
|
|
5092 return;
|
|
5093 } else {
|
|
5094 makeApi(sinon);
|
|
5095 }
|
|
5096 }());
|
|
5097
|
|
5098 /**
|
|
5099 * @depend util/core.js
|
|
5100 * @depend stub.js
|
|
5101 * @depend mock.js
|
|
5102 * @depend sandbox.js
|
|
5103 */
|
|
5104 /**
|
|
5105 * Test function, sandboxes fakes
|
|
5106 *
|
|
5107 * @author Christian Johansen ([email protected])
|
|
5108 * @license BSD
|
|
5109 *
|
|
5110 * Copyright (c) 2010-2013 Christian Johansen
|
|
5111 */
|
|
5112
|
|
5113 (function (sinon) {
|
|
5114 function makeApi(sinon) {
|
|
5115 function test(callback) {
|
|
5116 var type = typeof callback;
|
|
5117
|
|
5118 if (type != "function") {
|
|
5119 throw new TypeError("sinon.test needs to wrap a test function, got " + type);
|
|
5120 }
|
|
5121
|
|
5122 function sinonSandboxedTest() {
|
|
5123 var config = sinon.getConfig(sinon.config);
|
|
5124 config.injectInto = config.injectIntoThis && this || config.injectInto;
|
|
5125 var sandbox = sinon.sandbox.create(config);
|
|
5126 var exception, result;
|
|
5127 var doneIsWrapped = false;
|
|
5128 var argumentsCopy = Array.prototype.slice.call(arguments);
|
|
5129 if (argumentsCopy.length > 0 && typeof argumentsCopy[arguments.length - 1] == "function") {
|
|
5130 var oldDone = argumentsCopy[arguments.length - 1];
|
|
5131 argumentsCopy[arguments.length - 1] = function done(result) {
|
|
5132 if (result) {
|
|
5133 sandbox.restore();
|
|
5134 throw exception;
|
|
5135 } else {
|
|
5136 sandbox.verifyAndRestore();
|
|
5137 }
|
|
5138 oldDone(result);
|
|
5139 }
|
|
5140 doneIsWrapped = true;
|
|
5141 }
|
|
5142
|
|
5143 var args = argumentsCopy.concat(sandbox.args);
|
|
5144
|
|
5145 try {
|
|
5146 result = callback.apply(this, args);
|
|
5147 } catch (e) {
|
|
5148 exception = e;
|
|
5149 }
|
|
5150
|
|
5151 if (!doneIsWrapped) {
|
|
5152 if (typeof exception !== "undefined") {
|
|
5153 sandbox.restore();
|
|
5154 throw exception;
|
|
5155 } else {
|
|
5156 sandbox.verifyAndRestore();
|
|
5157 }
|
|
5158 }
|
|
5159
|
|
5160 return result;
|
|
5161 };
|
|
5162
|
|
5163 if (callback.length) {
|
|
5164 return function sinonAsyncSandboxedTest(callback) {
|
|
5165 return sinonSandboxedTest.apply(this, arguments);
|
|
5166 };
|
|
5167 }
|
|
5168
|
|
5169 return sinonSandboxedTest;
|
|
5170 }
|
|
5171
|
|
5172 test.config = {
|
|
5173 injectIntoThis: true,
|
|
5174 injectInto: null,
|
|
5175 properties: ["spy", "stub", "mock", "clock", "server", "requests"],
|
|
5176 useFakeTimers: true,
|
|
5177 useFakeServer: true
|
|
5178 };
|
|
5179
|
|
5180 sinon.test = test;
|
|
5181 return test;
|
|
5182 }
|
|
5183
|
|
5184 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
5185 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
5186
|
|
5187 function loadDependencies(require, exports, module) {
|
|
5188 var sinon = require("./util/core");
|
|
5189 require("./sandbox");
|
|
5190 module.exports = makeApi(sinon);
|
|
5191 }
|
|
5192
|
|
5193 if (isAMD) {
|
|
5194 define(loadDependencies);
|
|
5195 } else if (isNode) {
|
|
5196 loadDependencies(require, module.exports, module);
|
|
5197 } else if (!sinon) {
|
|
5198 return;
|
|
5199 } else {
|
|
5200 makeApi(sinon);
|
|
5201 }
|
|
5202 }(typeof sinon == "object" && sinon || null));
|
|
5203
|
|
5204 /**
|
|
5205 * @depend util/core.js
|
|
5206 * @depend test.js
|
|
5207 */
|
|
5208 /**
|
|
5209 * Test case, sandboxes all test functions
|
|
5210 *
|
|
5211 * @author Christian Johansen ([email protected])
|
|
5212 * @license BSD
|
|
5213 *
|
|
5214 * Copyright (c) 2010-2013 Christian Johansen
|
|
5215 */
|
|
5216
|
|
5217 (function (sinon) {
|
|
5218 function createTest(property, setUp, tearDown) {
|
|
5219 return function () {
|
|
5220 if (setUp) {
|
|
5221 setUp.apply(this, arguments);
|
|
5222 }
|
|
5223
|
|
5224 var exception, result;
|
|
5225
|
|
5226 try {
|
|
5227 result = property.apply(this, arguments);
|
|
5228 } catch (e) {
|
|
5229 exception = e;
|
|
5230 }
|
|
5231
|
|
5232 if (tearDown) {
|
|
5233 tearDown.apply(this, arguments);
|
|
5234 }
|
|
5235
|
|
5236 if (exception) {
|
|
5237 throw exception;
|
|
5238 }
|
|
5239
|
|
5240 return result;
|
|
5241 };
|
|
5242 }
|
|
5243
|
|
5244 function makeApi(sinon) {
|
|
5245 function testCase(tests, prefix) {
|
|
5246 /*jsl:ignore*/
|
|
5247 if (!tests || typeof tests != "object") {
|
|
5248 throw new TypeError("sinon.testCase needs an object with test functions");
|
|
5249 }
|
|
5250 /*jsl:end*/
|
|
5251
|
|
5252 prefix = prefix || "test";
|
|
5253 var rPrefix = new RegExp("^" + prefix);
|
|
5254 var methods = {}, testName, property, method;
|
|
5255 var setUp = tests.setUp;
|
|
5256 var tearDown = tests.tearDown;
|
|
5257
|
|
5258 for (testName in tests) {
|
|
5259 if (tests.hasOwnProperty(testName)) {
|
|
5260 property = tests[testName];
|
|
5261
|
|
5262 if (/^(setUp|tearDown)$/.test(testName)) {
|
|
5263 continue;
|
|
5264 }
|
|
5265
|
|
5266 if (typeof property == "function" && rPrefix.test(testName)) {
|
|
5267 method = property;
|
|
5268
|
|
5269 if (setUp || tearDown) {
|
|
5270 method = createTest(property, setUp, tearDown);
|
|
5271 }
|
|
5272
|
|
5273 methods[testName] = sinon.test(method);
|
|
5274 } else {
|
|
5275 methods[testName] = tests[testName];
|
|
5276 }
|
|
5277 }
|
|
5278 }
|
|
5279
|
|
5280 return methods;
|
|
5281 }
|
|
5282
|
|
5283 sinon.testCase = testCase;
|
|
5284 return testCase;
|
|
5285 }
|
|
5286
|
|
5287 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
5288 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
5289
|
|
5290 function loadDependencies(require, exports, module) {
|
|
5291 var sinon = require("./util/core");
|
|
5292 require("./test");
|
|
5293 module.exports = makeApi(sinon);
|
|
5294 }
|
|
5295
|
|
5296 if (isAMD) {
|
|
5297 define(loadDependencies);
|
|
5298 } else if (isNode) {
|
|
5299 loadDependencies(require, module.exports, module);
|
|
5300 } else if (!sinon) {
|
|
5301 return;
|
|
5302 } else {
|
|
5303 makeApi(sinon);
|
|
5304 }
|
|
5305 }(typeof sinon == "object" && sinon || null));
|
|
5306
|
|
5307 /**
|
|
5308 * @depend times_in_words.js
|
|
5309 * @depend util/core.js
|
|
5310 * @depend stub.js
|
|
5311 * @depend format.js
|
|
5312 */
|
|
5313 /**
|
|
5314 * Assertions matching the test spy retrieval interface.
|
|
5315 *
|
|
5316 * @author Christian Johansen ([email protected])
|
|
5317 * @license BSD
|
|
5318 *
|
|
5319 * Copyright (c) 2010-2013 Christian Johansen
|
|
5320 */
|
|
5321
|
|
5322 (function (sinon, global) {
|
|
5323 var slice = Array.prototype.slice;
|
|
5324
|
|
5325 function makeApi(sinon) {
|
|
5326 var assert;
|
|
5327
|
|
5328 function verifyIsStub() {
|
|
5329 var method;
|
|
5330
|
|
5331 for (var i = 0, l = arguments.length; i < l; ++i) {
|
|
5332 method = arguments[i];
|
|
5333
|
|
5334 if (!method) {
|
|
5335 assert.fail("fake is not a spy");
|
|
5336 }
|
|
5337
|
|
5338 if (typeof method != "function") {
|
|
5339 assert.fail(method + " is not a function");
|
|
5340 }
|
|
5341
|
|
5342 if (typeof method.getCall != "function") {
|
|
5343 assert.fail(method + " is not stubbed");
|
|
5344 }
|
|
5345 }
|
|
5346 }
|
|
5347
|
|
5348 function failAssertion(object, msg) {
|
|
5349 object = object || global;
|
|
5350 var failMethod = object.fail || assert.fail;
|
|
5351 failMethod.call(object, msg);
|
|
5352 }
|
|
5353
|
|
5354 function mirrorPropAsAssertion(name, method, message) {
|
|
5355 if (arguments.length == 2) {
|
|
5356 message = method;
|
|
5357 method = name;
|
|
5358 }
|
|
5359
|
|
5360 assert[name] = function (fake) {
|
|
5361 verifyIsStub(fake);
|
|
5362
|
|
5363 var args = slice.call(arguments, 1);
|
|
5364 var failed = false;
|
|
5365
|
|
5366 if (typeof method == "function") {
|
|
5367 failed = !method(fake);
|
|
5368 } else {
|
|
5369 failed = typeof fake[method] == "function" ?
|
|
5370 !fake[method].apply(fake, args) : !fake[method];
|
|
5371 }
|
|
5372
|
|
5373 if (failed) {
|
|
5374 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
|
|
5375 } else {
|
|
5376 assert.pass(name);
|
|
5377 }
|
|
5378 };
|
|
5379 }
|
|
5380
|
|
5381 function exposedName(prefix, prop) {
|
|
5382 return !prefix || /^fail/.test(prop) ? prop :
|
|
5383 prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
|
|
5384 }
|
|
5385
|
|
5386 assert = {
|
|
5387 failException: "AssertError",
|
|
5388
|
|
5389 fail: function fail(message) {
|
|
5390 var error = new Error(message);
|
|
5391 error.name = this.failException || assert.failException;
|
|
5392
|
|
5393 throw error;
|
|
5394 },
|
|
5395
|
|
5396 pass: function pass(assertion) {},
|
|
5397
|
|
5398 callOrder: function assertCallOrder() {
|
|
5399 verifyIsStub.apply(null, arguments);
|
|
5400 var expected = "", actual = "";
|
|
5401
|
|
5402 if (!sinon.calledInOrder(arguments)) {
|
|
5403 try {
|
|
5404 expected = [].join.call(arguments, ", ");
|
|
5405 var calls = slice.call(arguments);
|
|
5406 var i = calls.length;
|
|
5407 while (i) {
|
|
5408 if (!calls[--i].called) {
|
|
5409 calls.splice(i, 1);
|
|
5410 }
|
|
5411 }
|
|
5412 actual = sinon.orderByFirstCall(calls).join(", ");
|
|
5413 } catch (e) {
|
|
5414 // If this fails, we'll just fall back to the blank string
|
|
5415 }
|
|
5416
|
|
5417 failAssertion(this, "expected " + expected + " to be " +
|
|
5418 "called in order but were called as " + actual);
|
|
5419 } else {
|
|
5420 assert.pass("callOrder");
|
|
5421 }
|
|
5422 },
|
|
5423
|
|
5424 callCount: function assertCallCount(method, count) {
|
|
5425 verifyIsStub(method);
|
|
5426
|
|
5427 if (method.callCount != count) {
|
|
5428 var msg = "expected %n to be called " + sinon.timesInWords(count) +
|
|
5429 " but was called %c%C";
|
|
5430 failAssertion(this, method.printf(msg));
|
|
5431 } else {
|
|
5432 assert.pass("callCount");
|
|
5433 }
|
|
5434 },
|
|
5435
|
|
5436 expose: function expose(target, options) {
|
|
5437 if (!target) {
|
|
5438 throw new TypeError("target is null or undefined");
|
|
5439 }
|
|
5440
|
|
5441 var o = options || {};
|
|
5442 var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
|
|
5443 var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
|
|
5444
|
|
5445 for (var method in this) {
|
|
5446 if (method != "expose" && (includeFail || !/^(fail)/.test(method))) {
|
|
5447 target[exposedName(prefix, method)] = this[method];
|
|
5448 }
|
|
5449 }
|
|
5450
|
|
5451 return target;
|
|
5452 },
|
|
5453
|
|
5454 match: function match(actual, expectation) {
|
|
5455 var matcher = sinon.match(expectation);
|
|
5456 if (matcher.test(actual)) {
|
|
5457 assert.pass("match");
|
|
5458 } else {
|
|
5459 var formatted = [
|
|
5460 "expected value to match",
|
|
5461 " expected = " + sinon.format(expectation),
|
|
5462 " actual = " + sinon.format(actual)
|
|
5463 ]
|
|
5464 failAssertion(this, formatted.join("\n"));
|
|
5465 }
|
|
5466 }
|
|
5467 };
|
|
5468
|
|
5469 mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
|
|
5470 mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
|
|
5471 "expected %n to not have been called but was called %c%C");
|
|
5472 mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
|
|
5473 mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
|
|
5474 mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
|
|
5475 mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
|
|
5476 mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
|
|
5477 mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
|
|
5478 mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
|
|
5479 mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
|
|
5480 mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
|
|
5481 mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
|
|
5482 mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
|
|
5483 mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
|
|
5484 mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
|
|
5485 mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
|
|
5486 mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
|
|
5487 mirrorPropAsAssertion("threw", "%n did not throw exception%C");
|
|
5488 mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
|
|
5489
|
|
5490 sinon.assert = assert;
|
|
5491 return assert;
|
|
5492 }
|
|
5493
|
|
5494 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
5495 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
5496
|
|
5497 function loadDependencies(require, exports, module) {
|
|
5498 var sinon = require("./util/core");
|
|
5499 require("./match");
|
|
5500 module.exports = makeApi(sinon);
|
|
5501 }
|
|
5502
|
|
5503 if (isAMD) {
|
|
5504 define(loadDependencies);
|
|
5505 } else if (isNode) {
|
|
5506 loadDependencies(require, module.exports, module);
|
|
5507 } else if (!sinon) {
|
|
5508 return;
|
|
5509 } else {
|
|
5510 makeApi(sinon);
|
|
5511 }
|
|
5512
|
|
5513 }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
|
|
5514
|
|
5515 /**
|
|
5516 * @depend core.js
|
|
5517 * @depend ../extend.js
|
|
5518 * @depend event.js
|
|
5519 * @depend ../log_error.js
|
|
5520 */
|
|
5521 /**
|
|
5522 * Fake XDomainRequest object
|
|
5523 */
|
|
5524
|
|
5525 if (typeof sinon == "undefined") {
|
|
5526 this.sinon = {};
|
|
5527 }
|
|
5528
|
|
5529 // wrapper for global
|
|
5530 (function (global) {
|
|
5531 var xdr = { XDomainRequest: global.XDomainRequest };
|
|
5532 xdr.GlobalXDomainRequest = global.XDomainRequest;
|
|
5533 xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
|
|
5534 xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false;
|
|
5535
|
|
5536 function makeApi(sinon) {
|
|
5537 sinon.xdr = xdr;
|
|
5538
|
|
5539 function FakeXDomainRequest() {
|
|
5540 this.readyState = FakeXDomainRequest.UNSENT;
|
|
5541 this.requestBody = null;
|
|
5542 this.requestHeaders = {};
|
|
5543 this.status = 0;
|
|
5544 this.timeout = null;
|
|
5545
|
|
5546 if (typeof FakeXDomainRequest.onCreate == "function") {
|
|
5547 FakeXDomainRequest.onCreate(this);
|
|
5548 }
|
|
5549 }
|
|
5550
|
|
5551 function verifyState(xdr) {
|
|
5552 if (xdr.readyState !== FakeXDomainRequest.OPENED) {
|
|
5553 throw new Error("INVALID_STATE_ERR");
|
|
5554 }
|
|
5555
|
|
5556 if (xdr.sendFlag) {
|
|
5557 throw new Error("INVALID_STATE_ERR");
|
|
5558 }
|
|
5559 }
|
|
5560
|
|
5561 function verifyRequestSent(xdr) {
|
|
5562 if (xdr.readyState == FakeXDomainRequest.UNSENT) {
|
|
5563 throw new Error("Request not sent");
|
|
5564 }
|
|
5565 if (xdr.readyState == FakeXDomainRequest.DONE) {
|
|
5566 throw new Error("Request done");
|
|
5567 }
|
|
5568 }
|
|
5569
|
|
5570 function verifyResponseBodyType(body) {
|
|
5571 if (typeof body != "string") {
|
|
5572 var error = new Error("Attempted to respond to fake XDomainRequest with " +
|
|
5573 body + ", which is not a string.");
|
|
5574 error.name = "InvalidBodyException";
|
|
5575 throw error;
|
|
5576 }
|
|
5577 }
|
|
5578
|
|
5579 sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
|
|
5580 open: function open(method, url) {
|
|
5581 this.method = method;
|
|
5582 this.url = url;
|
|
5583
|
|
5584 this.responseText = null;
|
|
5585 this.sendFlag = false;
|
|
5586
|
|
5587 this.readyStateChange(FakeXDomainRequest.OPENED);
|
|
5588 },
|
|
5589
|
|
5590 readyStateChange: function readyStateChange(state) {
|
|
5591 this.readyState = state;
|
|
5592 var eventName = "";
|
|
5593 switch (this.readyState) {
|
|
5594 case FakeXDomainRequest.UNSENT:
|
|
5595 break;
|
|
5596 case FakeXDomainRequest.OPENED:
|
|
5597 break;
|
|
5598 case FakeXDomainRequest.LOADING:
|
|
5599 if (this.sendFlag) {
|
|
5600 //raise the progress event
|
|
5601 eventName = "onprogress";
|
|
5602 }
|
|
5603 break;
|
|
5604 case FakeXDomainRequest.DONE:
|
|
5605 if (this.isTimeout) {
|
|
5606 eventName = "ontimeout"
|
|
5607 } else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
|
|
5608 eventName = "onerror";
|
|
5609 } else {
|
|
5610 eventName = "onload"
|
|
5611 }
|
|
5612 break;
|
|
5613 }
|
|
5614
|
|
5615 // raising event (if defined)
|
|
5616 if (eventName) {
|
|
5617 if (typeof this[eventName] == "function") {
|
|
5618 try {
|
|
5619 this[eventName]();
|
|
5620 } catch (e) {
|
|
5621 sinon.logError("Fake XHR " + eventName + " handler", e);
|
|
5622 }
|
|
5623 }
|
|
5624 }
|
|
5625 },
|
|
5626
|
|
5627 send: function send(data) {
|
|
5628 verifyState(this);
|
|
5629
|
|
5630 if (!/^(get|head)$/i.test(this.method)) {
|
|
5631 this.requestBody = data;
|
|
5632 }
|
|
5633 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
|
|
5634
|
|
5635 this.errorFlag = false;
|
|
5636 this.sendFlag = true;
|
|
5637 this.readyStateChange(FakeXDomainRequest.OPENED);
|
|
5638
|
|
5639 if (typeof this.onSend == "function") {
|
|
5640 this.onSend(this);
|
|
5641 }
|
|
5642 },
|
|
5643
|
|
5644 abort: function abort() {
|
|
5645 this.aborted = true;
|
|
5646 this.responseText = null;
|
|
5647 this.errorFlag = true;
|
|
5648
|
|
5649 if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
|
|
5650 this.readyStateChange(sinon.FakeXDomainRequest.DONE);
|
|
5651 this.sendFlag = false;
|
|
5652 }
|
|
5653 },
|
|
5654
|
|
5655 setResponseBody: function setResponseBody(body) {
|
|
5656 verifyRequestSent(this);
|
|
5657 verifyResponseBodyType(body);
|
|
5658
|
|
5659 var chunkSize = this.chunkSize || 10;
|
|
5660 var index = 0;
|
|
5661 this.responseText = "";
|
|
5662
|
|
5663 do {
|
|
5664 this.readyStateChange(FakeXDomainRequest.LOADING);
|
|
5665 this.responseText += body.substring(index, index + chunkSize);
|
|
5666 index += chunkSize;
|
|
5667 } while (index < body.length);
|
|
5668
|
|
5669 this.readyStateChange(FakeXDomainRequest.DONE);
|
|
5670 },
|
|
5671
|
|
5672 respond: function respond(status, contentType, body) {
|
|
5673 // content-type ignored, since XDomainRequest does not carry this
|
|
5674 // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
|
|
5675 // test integration across browsers
|
|
5676 this.status = typeof status == "number" ? status : 200;
|
|
5677 this.setResponseBody(body || "");
|
|
5678 },
|
|
5679
|
|
5680 simulatetimeout: function simulatetimeout() {
|
|
5681 this.status = 0;
|
|
5682 this.isTimeout = true;
|
|
5683 // Access to this should actually throw an error
|
|
5684 this.responseText = undefined;
|
|
5685 this.readyStateChange(FakeXDomainRequest.DONE);
|
|
5686 }
|
|
5687 });
|
|
5688
|
|
5689 sinon.extend(FakeXDomainRequest, {
|
|
5690 UNSENT: 0,
|
|
5691 OPENED: 1,
|
|
5692 LOADING: 3,
|
|
5693 DONE: 4
|
|
5694 });
|
|
5695
|
|
5696 sinon.useFakeXDomainRequest = function useFakeXDomainRequest() {
|
|
5697 sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
|
|
5698 if (xdr.supportsXDR) {
|
|
5699 global.XDomainRequest = xdr.GlobalXDomainRequest;
|
|
5700 }
|
|
5701
|
|
5702 delete sinon.FakeXDomainRequest.restore;
|
|
5703
|
|
5704 if (keepOnCreate !== true) {
|
|
5705 delete sinon.FakeXDomainRequest.onCreate;
|
|
5706 }
|
|
5707 };
|
|
5708 if (xdr.supportsXDR) {
|
|
5709 global.XDomainRequest = sinon.FakeXDomainRequest;
|
|
5710 }
|
|
5711 return sinon.FakeXDomainRequest;
|
|
5712 };
|
|
5713
|
|
5714 sinon.FakeXDomainRequest = FakeXDomainRequest;
|
|
5715 }
|
|
5716
|
|
5717 var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
|
|
5718 var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
|
|
5719
|
|
5720 function loadDependencies(require, exports, module) {
|
|
5721 var sinon = require("./core");
|
|
5722 require("./event");
|
|
5723 makeApi(sinon);
|
|
5724 module.exports = sinon;
|
|
5725 }
|
|
5726
|
|
5727 if (isAMD) {
|
|
5728 define(loadDependencies);
|
|
5729 } else if (isNode) {
|
|
5730 loadDependencies(require, module.exports, module);
|
|
5731 } else {
|
|
5732 makeApi(sinon);
|
|
5733 }
|
|
5734 })(this);
|
|
5735
|
|
5736 return sinon;
|
|
5737 }));
|