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