1/** 2 * Sinon.JS 1.10.0, 2014/05/19 3 * 4 * @author Christian Johansen (christian@cjohansen.no) 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, christian@cjohansen.no 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 36this.sinon = (function () { 37var samsam, formatio; 38function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } } 39define.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 (christian@cjohansen.no) 622 * @license BSD 623 * 624 * Copyright (c) 2010-2013 Christian Johansen 625 */ 626 627var 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 (mail@maxantoni.de) 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 (christian@cjohansen.no) 1254 * @author Maximilian Antoni (mail@maxantoni.de) 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 (christian@cjohansen.no) 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 createCallProperties.call(this); 1597 1598 try { 1599 if (matching) { 1600 returnValue = matching.invoke(func, thisValue, args); 1601 } else { 1602 returnValue = (this.func || func).apply(thisValue, args); 1603 } 1604 1605 var thisCall = this.getCall(this.callCount - 1); 1606 if (thisCall.calledWithNew() && typeof returnValue !== 'object') { 1607 returnValue = thisValue; 1608 } 1609 } catch (e) { 1610 exception = e; 1611 } 1612 1613 push.call(this.exceptions, exception); 1614 push.call(this.returnValues, returnValue); 1615 1616 if (exception !== undefined) { 1617 throw exception; 1618 } 1619 1620 return returnValue; 1621 }, 1622 1623 named: function named(name) { 1624 this.displayName = name; 1625 return this; 1626 }, 1627 1628 getCall: function getCall(i) { 1629 if (i < 0 || i >= this.callCount) { 1630 return null; 1631 } 1632 1633 return sinon.spyCall(this, this.thisValues[i], this.args[i], 1634 this.returnValues[i], this.exceptions[i], 1635 this.callIds[i]); 1636 }, 1637 1638 getCalls: function () { 1639 var calls = []; 1640 var i; 1641 1642 for (i = 0; i < this.callCount; i++) { 1643 calls.push(this.getCall(i)); 1644 } 1645 1646 return calls; 1647 }, 1648 1649 calledBefore: function calledBefore(spyFn) { 1650 if (!this.called) { 1651 return false; 1652 } 1653 1654 if (!spyFn.called) { 1655 return true; 1656 } 1657 1658 return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; 1659 }, 1660 1661 calledAfter: function calledAfter(spyFn) { 1662 if (!this.called || !spyFn.called) { 1663 return false; 1664 } 1665 1666 return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; 1667 }, 1668 1669 withArgs: function () { 1670 var args = slice.call(arguments); 1671 1672 if (this.fakes) { 1673 var match = matchingFake(this.fakes, args, true); 1674 1675 if (match) { 1676 return match; 1677 } 1678 } else { 1679 this.fakes = []; 1680 } 1681 1682 var original = this; 1683 var fake = this._create(); 1684 fake.matchingAguments = args; 1685 fake.parent = this; 1686 push.call(this.fakes, fake); 1687 1688 fake.withArgs = function () { 1689 return original.withArgs.apply(original, arguments); 1690 }; 1691 1692 for (var i = 0; i < this.args.length; i++) { 1693 if (fake.matches(this.args[i])) { 1694 incrementCallCount.call(fake); 1695 push.call(fake.thisValues, this.thisValues[i]); 1696 push.call(fake.args, this.args[i]); 1697 push.call(fake.returnValues, this.returnValues[i]); 1698 push.call(fake.exceptions, this.exceptions[i]); 1699 push.call(fake.callIds, this.callIds[i]); 1700 } 1701 } 1702 createCallProperties.call(fake); 1703 1704 return fake; 1705 }, 1706 1707 matches: function (args, strict) { 1708 var margs = this.matchingAguments; 1709 1710 if (margs.length <= args.length && 1711 sinon.deepEqual(margs, args.slice(0, margs.length))) { 1712 return !strict || margs.length == args.length; 1713 } 1714 }, 1715 1716 printf: function (format) { 1717 var spy = this; 1718 var args = slice.call(arguments, 1); 1719 var formatter; 1720 1721 return (format || "").replace(/%(.)/g, function (match, specifyer) { 1722 formatter = spyApi.formatters[specifyer]; 1723 1724 if (typeof formatter == "function") { 1725 return formatter.call(null, spy, args); 1726 } else if (!isNaN(parseInt(specifyer, 10))) { 1727 return sinon.format(args[specifyer - 1]); 1728 } 1729 1730 return "%" + specifyer; 1731 }); 1732 } 1733 }; 1734 1735 function delegateToCalls(method, matchAny, actual, notCalled) { 1736 spyApi[method] = function () { 1737 if (!this.called) { 1738 if (notCalled) { 1739 return notCalled.apply(this, arguments); 1740 } 1741 return false; 1742 } 1743 1744 var currentCall; 1745 var matches = 0; 1746 1747 for (var i = 0, l = this.callCount; i < l; i += 1) { 1748 currentCall = this.getCall(i); 1749 1750 if (currentCall[actual || method].apply(currentCall, arguments)) { 1751 matches += 1; 1752 1753 if (matchAny) { 1754 return true; 1755 } 1756 } 1757 } 1758 1759 return matches === this.callCount; 1760 }; 1761 } 1762 1763 delegateToCalls("calledOn", true); 1764 delegateToCalls("alwaysCalledOn", false, "calledOn"); 1765 delegateToCalls("calledWith", true); 1766 delegateToCalls("calledWithMatch", true); 1767 delegateToCalls("alwaysCalledWith", false, "calledWith"); 1768 delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); 1769 delegateToCalls("calledWithExactly", true); 1770 delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); 1771 delegateToCalls("neverCalledWith", false, "notCalledWith", 1772 function () { return true; }); 1773 delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", 1774 function () { return true; }); 1775 delegateToCalls("threw", true); 1776 delegateToCalls("alwaysThrew", false, "threw"); 1777 delegateToCalls("returned", true); 1778 delegateToCalls("alwaysReturned", false, "returned"); 1779 delegateToCalls("calledWithNew", true); 1780 delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); 1781 delegateToCalls("callArg", false, "callArgWith", function () { 1782 throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); 1783 }); 1784 spyApi.callArgWith = spyApi.callArg; 1785 delegateToCalls("callArgOn", false, "callArgOnWith", function () { 1786 throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); 1787 }); 1788 spyApi.callArgOnWith = spyApi.callArgOn; 1789 delegateToCalls("yield", false, "yield", function () { 1790 throw new Error(this.toString() + " cannot yield since it was not yet invoked."); 1791 }); 1792 // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. 1793 spyApi.invokeCallback = spyApi.yield; 1794 delegateToCalls("yieldOn", false, "yieldOn", function () { 1795 throw new Error(this.toString() + " cannot yield since it was not yet invoked."); 1796 }); 1797 delegateToCalls("yieldTo", false, "yieldTo", function (property) { 1798 throw new Error(this.toString() + " cannot yield to '" + property + 1799 "' since it was not yet invoked."); 1800 }); 1801 delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { 1802 throw new Error(this.toString() + " cannot yield to '" + property + 1803 "' since it was not yet invoked."); 1804 }); 1805 1806 spyApi.formatters = { 1807 "c": function (spy) { 1808 return sinon.timesInWords(spy.callCount); 1809 }, 1810 1811 "n": function (spy) { 1812 return spy.toString(); 1813 }, 1814 1815 "C": function (spy) { 1816 var calls = []; 1817 1818 for (var i = 0, l = spy.callCount; i < l; ++i) { 1819 var stringifiedCall = " " + spy.getCall(i).toString(); 1820 if (/\n/.test(calls[i - 1])) { 1821 stringifiedCall = "\n" + stringifiedCall; 1822 } 1823 push.call(calls, stringifiedCall); 1824 } 1825 1826 return calls.length > 0 ? "\n" + calls.join("\n") : ""; 1827 }, 1828 1829 "t": function (spy) { 1830 var objects = []; 1831 1832 for (var i = 0, l = spy.callCount; i < l; ++i) { 1833 push.call(objects, sinon.format(spy.thisValues[i])); 1834 } 1835 1836 return objects.join(", "); 1837 }, 1838 1839 "*": function (spy, args) { 1840 var formatted = []; 1841 1842 for (var i = 0, l = args.length; i < l; ++i) { 1843 push.call(formatted, sinon.format(args[i])); 1844 } 1845 1846 return formatted.join(", "); 1847 } 1848 }; 1849 1850 sinon.extend(spy, spyApi); 1851 1852 spy.spyCall = sinon.spyCall; 1853 sinon.spy = spy; 1854 1855 if (typeof define === "function" && define.amd) { 1856 define(["module"], function(module) { module.exports = spy; }); 1857 } else if (commonJSModule) { 1858 module.exports = spy; 1859 } 1860}(typeof sinon == "object" && sinon || null)); 1861 1862/** 1863 * @depend ../sinon.js 1864 */ 1865/*jslint eqeqeq: false, onevar: false*/ 1866/*global module, require, sinon, process, setImmediate, setTimeout*/ 1867/** 1868 * Stub behavior 1869 * 1870 * @author Christian Johansen (christian@cjohansen.no) 1871 * @author Tim Fischbach (mail@timfischbach.de) 1872 * @license BSD 1873 * 1874 * Copyright (c) 2010-2013 Christian Johansen 1875 */ 1876 1877(function (sinon) { 1878 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 1879 1880 if (!sinon && commonJSModule) { 1881 sinon = require("../sinon"); 1882 } 1883 1884 if (!sinon) { 1885 return; 1886 } 1887 1888 var slice = Array.prototype.slice; 1889 var join = Array.prototype.join; 1890 var proto; 1891 1892 var nextTick = (function () { 1893 if (typeof process === "object" && typeof process.nextTick === "function") { 1894 return process.nextTick; 1895 } else if (typeof setImmediate === "function") { 1896 return setImmediate; 1897 } else { 1898 return function (callback) { 1899 setTimeout(callback, 0); 1900 }; 1901 } 1902 })(); 1903 1904 function throwsException(error, message) { 1905 if (typeof error == "string") { 1906 this.exception = new Error(message || ""); 1907 this.exception.name = error; 1908 } else if (!error) { 1909 this.exception = new Error("Error"); 1910 } else { 1911 this.exception = error; 1912 } 1913 1914 return this; 1915 } 1916 1917 function getCallback(behavior, args) { 1918 var callArgAt = behavior.callArgAt; 1919 1920 if (callArgAt < 0) { 1921 var callArgProp = behavior.callArgProp; 1922 1923 for (var i = 0, l = args.length; i < l; ++i) { 1924 if (!callArgProp && typeof args[i] == "function") { 1925 return args[i]; 1926 } 1927 1928 if (callArgProp && args[i] && 1929 typeof args[i][callArgProp] == "function") { 1930 return args[i][callArgProp]; 1931 } 1932 } 1933 1934 return null; 1935 } 1936 1937 return args[callArgAt]; 1938 } 1939 1940 function getCallbackError(behavior, func, args) { 1941 if (behavior.callArgAt < 0) { 1942 var msg; 1943 1944 if (behavior.callArgProp) { 1945 msg = sinon.functionName(behavior.stub) + 1946 " expected to yield to '" + behavior.callArgProp + 1947 "', but no object with such a property was passed."; 1948 } else { 1949 msg = sinon.functionName(behavior.stub) + 1950 " expected to yield, but no callback was passed."; 1951 } 1952 1953 if (args.length > 0) { 1954 msg += " Received [" + join.call(args, ", ") + "]"; 1955 } 1956 1957 return msg; 1958 } 1959 1960 return "argument at index " + behavior.callArgAt + " is not a function: " + func; 1961 } 1962 1963 function callCallback(behavior, args) { 1964 if (typeof behavior.callArgAt == "number") { 1965 var func = getCallback(behavior, args); 1966 1967 if (typeof func != "function") { 1968 throw new TypeError(getCallbackError(behavior, func, args)); 1969 } 1970 1971 if (behavior.callbackAsync) { 1972 nextTick(function() { 1973 func.apply(behavior.callbackContext, behavior.callbackArguments); 1974 }); 1975 } else { 1976 func.apply(behavior.callbackContext, behavior.callbackArguments); 1977 } 1978 } 1979 } 1980 1981 proto = { 1982 create: function(stub) { 1983 var behavior = sinon.extend({}, sinon.behavior); 1984 delete behavior.create; 1985 behavior.stub = stub; 1986 1987 return behavior; 1988 }, 1989 1990 isPresent: function() { 1991 return (typeof this.callArgAt == 'number' || 1992 this.exception || 1993 typeof this.returnArgAt == 'number' || 1994 this.returnThis || 1995 this.returnValueDefined); 1996 }, 1997 1998 invoke: function(context, args) { 1999 callCallback(this, args); 2000 2001 if (this.exception) { 2002 throw this.exception; 2003 } else if (typeof this.returnArgAt == 'number') { 2004 return args[this.returnArgAt]; 2005 } else if (this.returnThis) { 2006 return context; 2007 } 2008 2009 return this.returnValue; 2010 }, 2011 2012 onCall: function(index) { 2013 return this.stub.onCall(index); 2014 }, 2015 2016 onFirstCall: function() { 2017 return this.stub.onFirstCall(); 2018 }, 2019 2020 onSecondCall: function() { 2021 return this.stub.onSecondCall(); 2022 }, 2023 2024 onThirdCall: function() { 2025 return this.stub.onThirdCall(); 2026 }, 2027 2028 withArgs: function(/* arguments */) { 2029 throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' + 2030 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.'); 2031 }, 2032 2033 callsArg: function callsArg(pos) { 2034 if (typeof pos != "number") { 2035 throw new TypeError("argument index is not number"); 2036 } 2037 2038 this.callArgAt = pos; 2039 this.callbackArguments = []; 2040 this.callbackContext = undefined; 2041 this.callArgProp = undefined; 2042 this.callbackAsync = false; 2043 2044 return this; 2045 }, 2046 2047 callsArgOn: function callsArgOn(pos, context) { 2048 if (typeof pos != "number") { 2049 throw new TypeError("argument index is not number"); 2050 } 2051 if (typeof context != "object") { 2052 throw new TypeError("argument context is not an object"); 2053 } 2054 2055 this.callArgAt = pos; 2056 this.callbackArguments = []; 2057 this.callbackContext = context; 2058 this.callArgProp = undefined; 2059 this.callbackAsync = false; 2060 2061 return this; 2062 }, 2063 2064 callsArgWith: function callsArgWith(pos) { 2065 if (typeof pos != "number") { 2066 throw new TypeError("argument index is not number"); 2067 } 2068 2069 this.callArgAt = pos; 2070 this.callbackArguments = slice.call(arguments, 1); 2071 this.callbackContext = undefined; 2072 this.callArgProp = undefined; 2073 this.callbackAsync = false; 2074 2075 return this; 2076 }, 2077 2078 callsArgOnWith: function callsArgWith(pos, context) { 2079 if (typeof pos != "number") { 2080 throw new TypeError("argument index is not number"); 2081 } 2082 if (typeof context != "object") { 2083 throw new TypeError("argument context is not an object"); 2084 } 2085 2086 this.callArgAt = pos; 2087 this.callbackArguments = slice.call(arguments, 2); 2088 this.callbackContext = context; 2089 this.callArgProp = undefined; 2090 this.callbackAsync = false; 2091 2092 return this; 2093 }, 2094 2095 yields: function () { 2096 this.callArgAt = -1; 2097 this.callbackArguments = slice.call(arguments, 0); 2098 this.callbackContext = undefined; 2099 this.callArgProp = undefined; 2100 this.callbackAsync = false; 2101 2102 return this; 2103 }, 2104 2105 yieldsOn: function (context) { 2106 if (typeof context != "object") { 2107 throw new TypeError("argument context is not an object"); 2108 } 2109 2110 this.callArgAt = -1; 2111 this.callbackArguments = slice.call(arguments, 1); 2112 this.callbackContext = context; 2113 this.callArgProp = undefined; 2114 this.callbackAsync = false; 2115 2116 return this; 2117 }, 2118 2119 yieldsTo: function (prop) { 2120 this.callArgAt = -1; 2121 this.callbackArguments = slice.call(arguments, 1); 2122 this.callbackContext = undefined; 2123 this.callArgProp = prop; 2124 this.callbackAsync = false; 2125 2126 return this; 2127 }, 2128 2129 yieldsToOn: function (prop, context) { 2130 if (typeof context != "object") { 2131 throw new TypeError("argument context is not an object"); 2132 } 2133 2134 this.callArgAt = -1; 2135 this.callbackArguments = slice.call(arguments, 2); 2136 this.callbackContext = context; 2137 this.callArgProp = prop; 2138 this.callbackAsync = false; 2139 2140 return this; 2141 }, 2142 2143 2144 "throws": throwsException, 2145 throwsException: throwsException, 2146 2147 returns: function returns(value) { 2148 this.returnValue = value; 2149 this.returnValueDefined = true; 2150 2151 return this; 2152 }, 2153 2154 returnsArg: function returnsArg(pos) { 2155 if (typeof pos != "number") { 2156 throw new TypeError("argument index is not number"); 2157 } 2158 2159 this.returnArgAt = pos; 2160 2161 return this; 2162 }, 2163 2164 returnsThis: function returnsThis() { 2165 this.returnThis = true; 2166 2167 return this; 2168 } 2169 }; 2170 2171 // create asynchronous versions of callsArg* and yields* methods 2172 for (var method in proto) { 2173 // need to avoid creating anotherasync versions of the newly added async methods 2174 if (proto.hasOwnProperty(method) && 2175 method.match(/^(callsArg|yields)/) && 2176 !method.match(/Async/)) { 2177 proto[method + 'Async'] = (function (syncFnName) { 2178 return function () { 2179 var result = this[syncFnName].apply(this, arguments); 2180 this.callbackAsync = true; 2181 return result; 2182 }; 2183 })(method); 2184 } 2185 } 2186 2187 sinon.behavior = proto; 2188 2189 if (typeof define === "function" && define.amd) { 2190 define(["module"], function(module) { module.exports = proto; }); 2191 } else if (commonJSModule) { 2192 module.exports = proto; 2193 } 2194}(typeof sinon == "object" && sinon || null)); 2195 2196/** 2197 * @depend ../sinon.js 2198 * @depend spy.js 2199 * @depend behavior.js 2200 */ 2201/*jslint eqeqeq: false, onevar: false*/ 2202/*global module, require, sinon*/ 2203/** 2204 * Stub functions 2205 * 2206 * @author Christian Johansen (christian@cjohansen.no) 2207 * @license BSD 2208 * 2209 * Copyright (c) 2010-2013 Christian Johansen 2210 */ 2211 2212(function (sinon) { 2213 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 2214 2215 if (!sinon && commonJSModule) { 2216 sinon = require("../sinon"); 2217 } 2218 2219 if (!sinon) { 2220 return; 2221 } 2222 2223 function stub(object, property, func) { 2224 if (!!func && typeof func != "function") { 2225 throw new TypeError("Custom stub should be function"); 2226 } 2227 2228 var wrapper; 2229 2230 if (func) { 2231 wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; 2232 } else { 2233 wrapper = stub.create(); 2234 } 2235 2236 if (!object && typeof property === "undefined") { 2237 return sinon.stub.create(); 2238 } 2239 2240 if (typeof property === "undefined" && typeof object == "object") { 2241 for (var prop in object) { 2242 if (typeof object[prop] === "function") { 2243 stub(object, prop); 2244 } 2245 } 2246 2247 return object; 2248 } 2249 2250 return sinon.wrapMethod(object, property, wrapper); 2251 } 2252 2253 function getDefaultBehavior(stub) { 2254 return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); 2255 } 2256 2257 function getParentBehaviour(stub) { 2258 return (stub.parent && getCurrentBehavior(stub.parent)); 2259 } 2260 2261 function getCurrentBehavior(stub) { 2262 var behavior = stub.behaviors[stub.callCount - 1]; 2263 return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); 2264 } 2265 2266 var uuid = 0; 2267 2268 sinon.extend(stub, (function () { 2269 var proto = { 2270 create: function create() { 2271 var functionStub = function () { 2272 return getCurrentBehavior(functionStub).invoke(this, arguments); 2273 }; 2274 2275 functionStub.id = "stub#" + uuid++; 2276 var orig = functionStub; 2277 functionStub = sinon.spy.create(functionStub); 2278 functionStub.func = orig; 2279 2280 sinon.extend(functionStub, stub); 2281 functionStub._create = sinon.stub.create; 2282 functionStub.displayName = "stub"; 2283 functionStub.toString = sinon.functionToString; 2284 2285 functionStub.defaultBehavior = null; 2286 functionStub.behaviors = []; 2287 2288 return functionStub; 2289 }, 2290 2291 resetBehavior: function () { 2292 var i; 2293 2294 this.defaultBehavior = null; 2295 this.behaviors = []; 2296 2297 delete this.returnValue; 2298 delete this.returnArgAt; 2299 this.returnThis = false; 2300 2301 if (this.fakes) { 2302 for (i = 0; i < this.fakes.length; i++) { 2303 this.fakes[i].resetBehavior(); 2304 } 2305 } 2306 }, 2307 2308 onCall: function(index) { 2309 if (!this.behaviors[index]) { 2310 this.behaviors[index] = sinon.behavior.create(this); 2311 } 2312 2313 return this.behaviors[index]; 2314 }, 2315 2316 onFirstCall: function() { 2317 return this.onCall(0); 2318 }, 2319 2320 onSecondCall: function() { 2321 return this.onCall(1); 2322 }, 2323 2324 onThirdCall: function() { 2325 return this.onCall(2); 2326 } 2327 }; 2328 2329 for (var method in sinon.behavior) { 2330 if (sinon.behavior.hasOwnProperty(method) && 2331 !proto.hasOwnProperty(method) && 2332 method != 'create' && 2333 method != 'withArgs' && 2334 method != 'invoke') { 2335 proto[method] = (function(behaviorMethod) { 2336 return function() { 2337 this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); 2338 this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); 2339 return this; 2340 }; 2341 }(method)); 2342 } 2343 } 2344 2345 return proto; 2346 }())); 2347 2348 sinon.stub = stub; 2349 2350 if (typeof define === "function" && define.amd) { 2351 define(["module"], function(module) { module.exports = stub; }); 2352 } else if (commonJSModule) { 2353 module.exports = stub; 2354 } 2355}(typeof sinon == "object" && sinon || null)); 2356 2357/** 2358 * @depend ../sinon.js 2359 * @depend stub.js 2360 */ 2361/*jslint eqeqeq: false, onevar: false, nomen: false*/ 2362/*global module, require, sinon*/ 2363/** 2364 * Mock functions. 2365 * 2366 * @author Christian Johansen (christian@cjohansen.no) 2367 * @license BSD 2368 * 2369 * Copyright (c) 2010-2013 Christian Johansen 2370 */ 2371 2372(function (sinon) { 2373 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 2374 var push = [].push; 2375 var match; 2376 2377 if (!sinon && commonJSModule) { 2378 sinon = require("../sinon"); 2379 } 2380 2381 if (!sinon) { 2382 return; 2383 } 2384 2385 match = sinon.match; 2386 2387 if (!match && commonJSModule) { 2388 match = require("./match"); 2389 } 2390 2391 function mock(object) { 2392 if (!object) { 2393 return sinon.expectation.create("Anonymous mock"); 2394 } 2395 2396 return mock.create(object); 2397 } 2398 2399 sinon.mock = mock; 2400 2401 sinon.extend(mock, (function () { 2402 function each(collection, callback) { 2403 if (!collection) { 2404 return; 2405 } 2406 2407 for (var i = 0, l = collection.length; i < l; i += 1) { 2408 callback(collection[i]); 2409 } 2410 } 2411 2412 return { 2413 create: function create(object) { 2414 if (!object) { 2415 throw new TypeError("object is null"); 2416 } 2417 2418 var mockObject = sinon.extend({}, mock); 2419 mockObject.object = object; 2420 delete mockObject.create; 2421 2422 return mockObject; 2423 }, 2424 2425 expects: function expects(method) { 2426 if (!method) { 2427 throw new TypeError("method is falsy"); 2428 } 2429 2430 if (!this.expectations) { 2431 this.expectations = {}; 2432 this.proxies = []; 2433 } 2434 2435 if (!this.expectations[method]) { 2436 this.expectations[method] = []; 2437 var mockObject = this; 2438 2439 sinon.wrapMethod(this.object, method, function () { 2440 return mockObject.invokeMethod(method, this, arguments); 2441 }); 2442 2443 push.call(this.proxies, method); 2444 } 2445 2446 var expectation = sinon.expectation.create(method); 2447 push.call(this.expectations[method], expectation); 2448 2449 return expectation; 2450 }, 2451 2452 restore: function restore() { 2453 var object = this.object; 2454 2455 each(this.proxies, function (proxy) { 2456 if (typeof object[proxy].restore == "function") { 2457 object[proxy].restore(); 2458 } 2459 }); 2460 }, 2461 2462 verify: function verify() { 2463 var expectations = this.expectations || {}; 2464 var messages = [], met = []; 2465 2466 each(this.proxies, function (proxy) { 2467 each(expectations[proxy], function (expectation) { 2468 if (!expectation.met()) { 2469 push.call(messages, expectation.toString()); 2470 } else { 2471 push.call(met, expectation.toString()); 2472 } 2473 }); 2474 }); 2475 2476 this.restore(); 2477 2478 if (messages.length > 0) { 2479 sinon.expectation.fail(messages.concat(met).join("\n")); 2480 } else { 2481 sinon.expectation.pass(messages.concat(met).join("\n")); 2482 } 2483 2484 return true; 2485 }, 2486 2487 invokeMethod: function invokeMethod(method, thisValue, args) { 2488 var expectations = this.expectations && this.expectations[method]; 2489 var length = expectations && expectations.length || 0, i; 2490 2491 for (i = 0; i < length; i += 1) { 2492 if (!expectations[i].met() && 2493 expectations[i].allowsCall(thisValue, args)) { 2494 return expectations[i].apply(thisValue, args); 2495 } 2496 } 2497 2498 var messages = [], available, exhausted = 0; 2499 2500 for (i = 0; i < length; i += 1) { 2501 if (expectations[i].allowsCall(thisValue, args)) { 2502 available = available || expectations[i]; 2503 } else { 2504 exhausted += 1; 2505 } 2506 push.call(messages, " " + expectations[i].toString()); 2507 } 2508 2509 if (exhausted === 0) { 2510 return available.apply(thisValue, args); 2511 } 2512 2513 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ 2514 proxy: method, 2515 args: args 2516 })); 2517 2518 sinon.expectation.fail(messages.join("\n")); 2519 } 2520 }; 2521 }())); 2522 2523 var times = sinon.timesInWords; 2524 2525 sinon.expectation = (function () { 2526 var slice = Array.prototype.slice; 2527 var _invoke = sinon.spy.invoke; 2528 2529 function callCountInWords(callCount) { 2530 if (callCount == 0) { 2531 return "never called"; 2532 } else { 2533 return "called " + times(callCount); 2534 } 2535 } 2536 2537 function expectedCallCountInWords(expectation) { 2538 var min = expectation.minCalls; 2539 var max = expectation.maxCalls; 2540 2541 if (typeof min == "number" && typeof max == "number") { 2542 var str = times(min); 2543 2544 if (min != max) { 2545 str = "at least " + str + " and at most " + times(max); 2546 } 2547 2548 return str; 2549 } 2550 2551 if (typeof min == "number") { 2552 return "at least " + times(min); 2553 } 2554 2555 return "at most " + times(max); 2556 } 2557 2558 function receivedMinCalls(expectation) { 2559 var hasMinLimit = typeof expectation.minCalls == "number"; 2560 return !hasMinLimit || expectation.callCount >= expectation.minCalls; 2561 } 2562 2563 function receivedMaxCalls(expectation) { 2564 if (typeof expectation.maxCalls != "number") { 2565 return false; 2566 } 2567 2568 return expectation.callCount == expectation.maxCalls; 2569 } 2570 2571 function verifyMatcher(possibleMatcher, arg){ 2572 if (match && match.isMatcher(possibleMatcher)) { 2573 return possibleMatcher.test(arg); 2574 } else { 2575 return true; 2576 } 2577 } 2578 2579 return { 2580 minCalls: 1, 2581 maxCalls: 1, 2582 2583 create: function create(methodName) { 2584 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); 2585 delete expectation.create; 2586 expectation.method = methodName; 2587 2588 return expectation; 2589 }, 2590 2591 invoke: function invoke(func, thisValue, args) { 2592 this.verifyCallAllowed(thisValue, args); 2593 2594 return _invoke.apply(this, arguments); 2595 }, 2596 2597 atLeast: function atLeast(num) { 2598 if (typeof num != "number") { 2599 throw new TypeError("'" + num + "' is not number"); 2600 } 2601 2602 if (!this.limitsSet) { 2603 this.maxCalls = null; 2604 this.limitsSet = true; 2605 } 2606 2607 this.minCalls = num; 2608 2609 return this; 2610 }, 2611 2612 atMost: function atMost(num) { 2613 if (typeof num != "number") { 2614 throw new TypeError("'" + num + "' is not number"); 2615 } 2616 2617 if (!this.limitsSet) { 2618 this.minCalls = null; 2619 this.limitsSet = true; 2620 } 2621 2622 this.maxCalls = num; 2623 2624 return this; 2625 }, 2626 2627 never: function never() { 2628 return this.exactly(0); 2629 }, 2630 2631 once: function once() { 2632 return this.exactly(1); 2633 }, 2634 2635 twice: function twice() { 2636 return this.exactly(2); 2637 }, 2638 2639 thrice: function thrice() { 2640 return this.exactly(3); 2641 }, 2642 2643 exactly: function exactly(num) { 2644 if (typeof num != "number") { 2645 throw new TypeError("'" + num + "' is not a number"); 2646 } 2647 2648 this.atLeast(num); 2649 return this.atMost(num); 2650 }, 2651 2652 met: function met() { 2653 return !this.failed && receivedMinCalls(this); 2654 }, 2655 2656 verifyCallAllowed: function verifyCallAllowed(thisValue, args) { 2657 if (receivedMaxCalls(this)) { 2658 this.failed = true; 2659 sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); 2660 } 2661 2662 if ("expectedThis" in this && this.expectedThis !== thisValue) { 2663 sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + 2664 this.expectedThis); 2665 } 2666 2667 if (!("expectedArguments" in this)) { 2668 return; 2669 } 2670 2671 if (!args) { 2672 sinon.expectation.fail(this.method + " received no arguments, expected " + 2673 sinon.format(this.expectedArguments)); 2674 } 2675 2676 if (args.length < this.expectedArguments.length) { 2677 sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + 2678 "), expected " + sinon.format(this.expectedArguments)); 2679 } 2680 2681 if (this.expectsExactArgCount && 2682 args.length != this.expectedArguments.length) { 2683 sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + 2684 "), expected " + sinon.format(this.expectedArguments)); 2685 } 2686 2687 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { 2688 2689 if (!verifyMatcher(this.expectedArguments[i],args[i])) { 2690 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + 2691 ", didn't match " + this.expectedArguments.toString()); 2692 } 2693 2694 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { 2695 sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + 2696 ", expected " + sinon.format(this.expectedArguments)); 2697 } 2698 } 2699 }, 2700 2701 allowsCall: function allowsCall(thisValue, args) { 2702 if (this.met() && receivedMaxCalls(this)) { 2703 return false; 2704 } 2705 2706 if ("expectedThis" in this && this.expectedThis !== thisValue) { 2707 return false; 2708 } 2709 2710 if (!("expectedArguments" in this)) { 2711 return true; 2712 } 2713 2714 args = args || []; 2715 2716 if (args.length < this.expectedArguments.length) { 2717 return false; 2718 } 2719 2720 if (this.expectsExactArgCount && 2721 args.length != this.expectedArguments.length) { 2722 return false; 2723 } 2724 2725 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { 2726 if (!verifyMatcher(this.expectedArguments[i],args[i])) { 2727 return false; 2728 } 2729 2730 if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { 2731 return false; 2732 } 2733 } 2734 2735 return true; 2736 }, 2737 2738 withArgs: function withArgs() { 2739 this.expectedArguments = slice.call(arguments); 2740 return this; 2741 }, 2742 2743 withExactArgs: function withExactArgs() { 2744 this.withArgs.apply(this, arguments); 2745 this.expectsExactArgCount = true; 2746 return this; 2747 }, 2748 2749 on: function on(thisValue) { 2750 this.expectedThis = thisValue; 2751 return this; 2752 }, 2753 2754 toString: function () { 2755 var args = (this.expectedArguments || []).slice(); 2756 2757 if (!this.expectsExactArgCount) { 2758 push.call(args, "[...]"); 2759 } 2760 2761 var callStr = sinon.spyCall.toString.call({ 2762 proxy: this.method || "anonymous mock expectation", 2763 args: args 2764 }); 2765 2766 var message = callStr.replace(", [...", "[, ...") + " " + 2767 expectedCallCountInWords(this); 2768 2769 if (this.met()) { 2770 return "Expectation met: " + message; 2771 } 2772 2773 return "Expected " + message + " (" + 2774 callCountInWords(this.callCount) + ")"; 2775 }, 2776 2777 verify: function verify() { 2778 if (!this.met()) { 2779 sinon.expectation.fail(this.toString()); 2780 } else { 2781 sinon.expectation.pass(this.toString()); 2782 } 2783 2784 return true; 2785 }, 2786 2787 pass: function(message) { 2788 sinon.assert.pass(message); 2789 }, 2790 fail: function (message) { 2791 var exception = new Error(message); 2792 exception.name = "ExpectationError"; 2793 2794 throw exception; 2795 } 2796 }; 2797 }()); 2798 2799 sinon.mock = mock; 2800 2801 if (typeof define === "function" && define.amd) { 2802 define(["module"], function(module) { module.exports = mock; }); 2803 } else if (commonJSModule) { 2804 module.exports = mock; 2805 } 2806}(typeof sinon == "object" && sinon || null)); 2807 2808/** 2809 * @depend ../sinon.js 2810 * @depend stub.js 2811 * @depend mock.js 2812 */ 2813/*jslint eqeqeq: false, onevar: false, forin: true*/ 2814/*global module, require, sinon*/ 2815/** 2816 * Collections of stubs, spies and mocks. 2817 * 2818 * @author Christian Johansen (christian@cjohansen.no) 2819 * @license BSD 2820 * 2821 * Copyright (c) 2010-2013 Christian Johansen 2822 */ 2823 2824(function (sinon) { 2825 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 2826 var push = [].push; 2827 var hasOwnProperty = Object.prototype.hasOwnProperty; 2828 2829 if (!sinon && commonJSModule) { 2830 sinon = require("../sinon"); 2831 } 2832 2833 if (!sinon) { 2834 return; 2835 } 2836 2837 function getFakes(fakeCollection) { 2838 if (!fakeCollection.fakes) { 2839 fakeCollection.fakes = []; 2840 } 2841 2842 return fakeCollection.fakes; 2843 } 2844 2845 function each(fakeCollection, method) { 2846 var fakes = getFakes(fakeCollection); 2847 2848 for (var i = 0, l = fakes.length; i < l; i += 1) { 2849 if (typeof fakes[i][method] == "function") { 2850 fakes[i][method](); 2851 } 2852 } 2853 } 2854 2855 function compact(fakeCollection) { 2856 var fakes = getFakes(fakeCollection); 2857 var i = 0; 2858 while (i < fakes.length) { 2859 fakes.splice(i, 1); 2860 } 2861 } 2862 2863 var collection = { 2864 verify: function resolve() { 2865 each(this, "verify"); 2866 }, 2867 2868 restore: function restore() { 2869 each(this, "restore"); 2870 compact(this); 2871 }, 2872 2873 verifyAndRestore: function verifyAndRestore() { 2874 var exception; 2875 2876 try { 2877 this.verify(); 2878 } catch (e) { 2879 exception = e; 2880 } 2881 2882 this.restore(); 2883 2884 if (exception) { 2885 throw exception; 2886 } 2887 }, 2888 2889 add: function add(fake) { 2890 push.call(getFakes(this), fake); 2891 return fake; 2892 }, 2893 2894 spy: function spy() { 2895 return this.add(sinon.spy.apply(sinon, arguments)); 2896 }, 2897 2898 stub: function stub(object, property, value) { 2899 if (property) { 2900 var original = object[property]; 2901 2902 if (typeof original != "function") { 2903 if (!hasOwnProperty.call(object, property)) { 2904 throw new TypeError("Cannot stub non-existent own property " + property); 2905 } 2906 2907 object[property] = value; 2908 2909 return this.add({ 2910 restore: function () { 2911 object[property] = original; 2912 } 2913 }); 2914 } 2915 } 2916 if (!property && !!object && typeof object == "object") { 2917 var stubbedObj = sinon.stub.apply(sinon, arguments); 2918 2919 for (var prop in stubbedObj) { 2920 if (typeof stubbedObj[prop] === "function") { 2921 this.add(stubbedObj[prop]); 2922 } 2923 } 2924 2925 return stubbedObj; 2926 } 2927 2928 return this.add(sinon.stub.apply(sinon, arguments)); 2929 }, 2930 2931 mock: function mock() { 2932 return this.add(sinon.mock.apply(sinon, arguments)); 2933 }, 2934 2935 inject: function inject(obj) { 2936 var col = this; 2937 2938 obj.spy = function () { 2939 return col.spy.apply(col, arguments); 2940 }; 2941 2942 obj.stub = function () { 2943 return col.stub.apply(col, arguments); 2944 }; 2945 2946 obj.mock = function () { 2947 return col.mock.apply(col, arguments); 2948 }; 2949 2950 return obj; 2951 } 2952 }; 2953 2954 sinon.collection = collection; 2955 2956 if (typeof define === "function" && define.amd) { 2957 define(["module"], function(module) { module.exports = collection; }); 2958 } else if (commonJSModule) { 2959 module.exports = collection; 2960 } 2961}(typeof sinon == "object" && sinon || null)); 2962 2963/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ 2964/*global module, require, window*/ 2965/** 2966 * Fake timer API 2967 * setTimeout 2968 * setInterval 2969 * clearTimeout 2970 * clearInterval 2971 * tick 2972 * reset 2973 * Date 2974 * 2975 * Inspired by jsUnitMockTimeOut from JsUnit 2976 * 2977 * @author Christian Johansen (christian@cjohansen.no) 2978 * @license BSD 2979 * 2980 * Copyright (c) 2010-2013 Christian Johansen 2981 */ 2982 2983if (typeof sinon == "undefined") { 2984 var sinon = {}; 2985} 2986 2987(function (global) { 2988 // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() 2989 // browsers, a number. 2990 // see https://github.com/cjohansen/Sinon.JS/pull/436 2991 var timeoutResult = setTimeout(function() {}, 0); 2992 var addTimerReturnsObject = typeof timeoutResult === 'object'; 2993 clearTimeout(timeoutResult); 2994 2995 var id = 1; 2996 2997 function addTimer(args, recurring) { 2998 if (args.length === 0) { 2999 throw new Error("Function requires at least 1 parameter"); 3000 } 3001 3002 if (typeof args[0] === "undefined") { 3003 throw new Error("Callback must be provided to timer calls"); 3004 } 3005 3006 var toId = id++; 3007 var delay = args[1] || 0; 3008 3009 if (!this.timeouts) { 3010 this.timeouts = {}; 3011 } 3012 3013 this.timeouts[toId] = { 3014 id: toId, 3015 func: args[0], 3016 callAt: this.now + delay, 3017 invokeArgs: Array.prototype.slice.call(args, 2) 3018 }; 3019 3020 if (recurring === true) { 3021 this.timeouts[toId].interval = delay; 3022 } 3023 3024 if (addTimerReturnsObject) { 3025 return { 3026 id: toId, 3027 ref: function() {}, 3028 unref: function() {} 3029 }; 3030 } 3031 else { 3032 return toId; 3033 } 3034 } 3035 3036 function parseTime(str) { 3037 if (!str) { 3038 return 0; 3039 } 3040 3041 var strings = str.split(":"); 3042 var l = strings.length, i = l; 3043 var ms = 0, parsed; 3044 3045 if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { 3046 throw new Error("tick only understands numbers and 'h:m:s'"); 3047 } 3048 3049 while (i--) { 3050 parsed = parseInt(strings[i], 10); 3051 3052 if (parsed >= 60) { 3053 throw new Error("Invalid time " + str); 3054 } 3055 3056 ms += parsed * Math.pow(60, (l - i - 1)); 3057 } 3058 3059 return ms * 1000; 3060 } 3061 3062 function createObject(object) { 3063 var newObject; 3064 3065 if (Object.create) { 3066 newObject = Object.create(object); 3067 } else { 3068 var F = function () {}; 3069 F.prototype = object; 3070 newObject = new F(); 3071 } 3072 3073 newObject.Date.clock = newObject; 3074 return newObject; 3075 } 3076 3077 sinon.clock = { 3078 now: 0, 3079 3080 create: function create(now) { 3081 var clock = createObject(this); 3082 3083 if (typeof now == "number") { 3084 clock.now = now; 3085 } 3086 3087 if (!!now && typeof now == "object") { 3088 throw new TypeError("now should be milliseconds since UNIX epoch"); 3089 } 3090 3091 return clock; 3092 }, 3093 3094 setTimeout: function setTimeout(callback, timeout) { 3095 return addTimer.call(this, arguments, false); 3096 }, 3097 3098 clearTimeout: function clearTimeout(timerId) { 3099 if (!this.timeouts) { 3100 this.timeouts = []; 3101 } 3102 // in Node, timerId is an object with .ref()/.unref(), and 3103 // its .id field is the actual timer id. 3104 if (typeof timerId === 'object') { 3105 timerId = timerId.id 3106 } 3107 if (timerId in this.timeouts) { 3108 delete this.timeouts[timerId]; 3109 } 3110 }, 3111 3112 setInterval: function setInterval(callback, timeout) { 3113 return addTimer.call(this, arguments, true); 3114 }, 3115 3116 clearInterval: function clearInterval(timerId) { 3117 this.clearTimeout(timerId); 3118 }, 3119 3120 setImmediate: function setImmediate(callback) { 3121 var passThruArgs = Array.prototype.slice.call(arguments, 1); 3122 3123 return addTimer.call(this, [callback, 0].concat(passThruArgs), false); 3124 }, 3125 3126 clearImmediate: function clearImmediate(timerId) { 3127 this.clearTimeout(timerId); 3128 }, 3129 3130 tick: function tick(ms) { 3131 ms = typeof ms == "number" ? ms : parseTime(ms); 3132 var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; 3133 var timer = this.firstTimerInRange(tickFrom, tickTo); 3134 3135 var firstException; 3136 while (timer && tickFrom <= tickTo) { 3137 if (this.timeouts[timer.id]) { 3138 tickFrom = this.now = timer.callAt; 3139 try { 3140 this.callTimer(timer); 3141 } catch (e) { 3142 firstException = firstException || e; 3143 } 3144 } 3145 3146 timer = this.firstTimerInRange(previous, tickTo); 3147 previous = tickFrom; 3148 } 3149 3150 this.now = tickTo; 3151 3152 if (firstException) { 3153 throw firstException; 3154 } 3155 3156 return this.now; 3157 }, 3158 3159 firstTimerInRange: function (from, to) { 3160 var timer, smallest = null, originalTimer; 3161 3162 for (var id in this.timeouts) { 3163 if (this.timeouts.hasOwnProperty(id)) { 3164 if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { 3165 continue; 3166 } 3167 3168 if (smallest === null || this.timeouts[id].callAt < smallest) { 3169 originalTimer = this.timeouts[id]; 3170 smallest = this.timeouts[id].callAt; 3171 3172 timer = { 3173 func: this.timeouts[id].func, 3174 callAt: this.timeouts[id].callAt, 3175 interval: this.timeouts[id].interval, 3176 id: this.timeouts[id].id, 3177 invokeArgs: this.timeouts[id].invokeArgs 3178 }; 3179 } 3180 } 3181 } 3182 3183 return timer || null; 3184 }, 3185 3186 callTimer: function (timer) { 3187 if (typeof timer.interval == "number") { 3188 this.timeouts[timer.id].callAt += timer.interval; 3189 } else { 3190 delete this.timeouts[timer.id]; 3191 } 3192 3193 try { 3194 if (typeof timer.func == "function") { 3195 timer.func.apply(null, timer.invokeArgs); 3196 } else { 3197 eval(timer.func); 3198 } 3199 } catch (e) { 3200 var exception = e; 3201 } 3202 3203 if (!this.timeouts[timer.id]) { 3204 if (exception) { 3205 throw exception; 3206 } 3207 return; 3208 } 3209 3210 if (exception) { 3211 throw exception; 3212 } 3213 }, 3214 3215 reset: function reset() { 3216 this.timeouts = {}; 3217 }, 3218 3219 Date: (function () { 3220 var NativeDate = Date; 3221 3222 function ClockDate(year, month, date, hour, minute, second, ms) { 3223 // Defensive and verbose to avoid potential harm in passing 3224 // explicit undefined when user does not pass argument 3225 switch (arguments.length) { 3226 case 0: 3227 return new NativeDate(ClockDate.clock.now); 3228 case 1: 3229 return new NativeDate(year); 3230 case 2: 3231 return new NativeDate(year, month); 3232 case 3: 3233 return new NativeDate(year, month, date); 3234 case 4: 3235 return new NativeDate(year, month, date, hour); 3236 case 5: 3237 return new NativeDate(year, month, date, hour, minute); 3238 case 6: 3239 return new NativeDate(year, month, date, hour, minute, second); 3240 default: 3241 return new NativeDate(year, month, date, hour, minute, second, ms); 3242 } 3243 } 3244 3245 return mirrorDateProperties(ClockDate, NativeDate); 3246 }()) 3247 }; 3248 3249 function mirrorDateProperties(target, source) { 3250 if (source.now) { 3251 target.now = function now() { 3252 return target.clock.now; 3253 }; 3254 } else { 3255 delete target.now; 3256 } 3257 3258 if (source.toSource) { 3259 target.toSource = function toSource() { 3260 return source.toSource(); 3261 }; 3262 } else { 3263 delete target.toSource; 3264 } 3265 3266 target.toString = function toString() { 3267 return source.toString(); 3268 }; 3269 3270 target.prototype = source.prototype; 3271 target.parse = source.parse; 3272 target.UTC = source.UTC; 3273 target.prototype.toUTCString = source.prototype.toUTCString; 3274 3275 for (var prop in source) { 3276 if (source.hasOwnProperty(prop)) { 3277 target[prop] = source[prop]; 3278 } 3279 } 3280 3281 return target; 3282 } 3283 3284 var methods = ["Date", "setTimeout", "setInterval", 3285 "clearTimeout", "clearInterval"]; 3286 3287 if (typeof global.setImmediate !== "undefined") { 3288 methods.push("setImmediate"); 3289 } 3290 3291 if (typeof global.clearImmediate !== "undefined") { 3292 methods.push("clearImmediate"); 3293 } 3294 3295 function restore() { 3296 var method; 3297 3298 for (var i = 0, l = this.methods.length; i < l; i++) { 3299 method = this.methods[i]; 3300 3301 if (global[method].hadOwnProperty) { 3302 global[method] = this["_" + method]; 3303 } else { 3304 try { 3305 delete global[method]; 3306 } catch (e) {} 3307 } 3308 } 3309 3310 // Prevent multiple executions which will completely remove these props 3311 this.methods = []; 3312 } 3313 3314 function stubGlobal(method, clock) { 3315 clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); 3316 clock["_" + method] = global[method]; 3317 3318 if (method == "Date") { 3319 var date = mirrorDateProperties(clock[method], global[method]); 3320 global[method] = date; 3321 } else { 3322 global[method] = function () { 3323 return clock[method].apply(clock, arguments); 3324 }; 3325 3326 for (var prop in clock[method]) { 3327 if (clock[method].hasOwnProperty(prop)) { 3328 global[method][prop] = clock[method][prop]; 3329 } 3330 } 3331 } 3332 3333 global[method].clock = clock; 3334 } 3335 3336 sinon.useFakeTimers = function useFakeTimers(now) { 3337 var clock = sinon.clock.create(now); 3338 clock.restore = restore; 3339 clock.methods = Array.prototype.slice.call(arguments, 3340 typeof now == "number" ? 1 : 0); 3341 3342 if (clock.methods.length === 0) { 3343 clock.methods = methods; 3344 } 3345 3346 for (var i = 0, l = clock.methods.length; i < l; i++) { 3347 stubGlobal(clock.methods[i], clock); 3348 } 3349 3350 return clock; 3351 }; 3352}(typeof global != "undefined" && typeof global !== "function" ? global : this)); 3353 3354sinon.timers = { 3355 setTimeout: setTimeout, 3356 clearTimeout: clearTimeout, 3357 setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), 3358 clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), 3359 setInterval: setInterval, 3360 clearInterval: clearInterval, 3361 Date: Date 3362}; 3363 3364if (typeof module !== 'undefined' && module.exports) { 3365 module.exports = sinon; 3366} 3367 3368/*jslint eqeqeq: false, onevar: false*/ 3369/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ 3370/** 3371 * Minimal Event interface implementation 3372 * 3373 * Original implementation by Sven Fuchs: https://gist.github.com/995028 3374 * Modifications and tests by Christian Johansen. 3375 * 3376 * @author Sven Fuchs (svenfuchs@artweb-design.de) 3377 * @author Christian Johansen (christian@cjohansen.no) 3378 * @license BSD 3379 * 3380 * Copyright (c) 2011 Sven Fuchs, Christian Johansen 3381 */ 3382 3383if (typeof sinon == "undefined") { 3384 this.sinon = {}; 3385} 3386 3387(function () { 3388 var push = [].push; 3389 3390 sinon.Event = function Event(type, bubbles, cancelable, target) { 3391 this.initEvent(type, bubbles, cancelable, target); 3392 }; 3393 3394 sinon.Event.prototype = { 3395 initEvent: function(type, bubbles, cancelable, target) { 3396 this.type = type; 3397 this.bubbles = bubbles; 3398 this.cancelable = cancelable; 3399 this.target = target; 3400 }, 3401 3402 stopPropagation: function () {}, 3403 3404 preventDefault: function () { 3405 this.defaultPrevented = true; 3406 } 3407 }; 3408 3409 sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { 3410 this.initEvent(type, false, false, target); 3411 this.loaded = progressEventRaw.loaded || null; 3412 this.total = progressEventRaw.total || null; 3413 }; 3414 3415 sinon.ProgressEvent.prototype = new sinon.Event(); 3416 3417 sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; 3418 3419 sinon.CustomEvent = function CustomEvent(type, customData, target) { 3420 this.initEvent(type, false, false, target); 3421 this.detail = customData.detail || null; 3422 }; 3423 3424 sinon.CustomEvent.prototype = new sinon.Event(); 3425 3426 sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; 3427 3428 sinon.EventTarget = { 3429 addEventListener: function addEventListener(event, listener) { 3430 this.eventListeners = this.eventListeners || {}; 3431 this.eventListeners[event] = this.eventListeners[event] || []; 3432 push.call(this.eventListeners[event], listener); 3433 }, 3434 3435 removeEventListener: function removeEventListener(event, listener) { 3436 var listeners = this.eventListeners && this.eventListeners[event] || []; 3437 3438 for (var i = 0, l = listeners.length; i < l; ++i) { 3439 if (listeners[i] == listener) { 3440 return listeners.splice(i, 1); 3441 } 3442 } 3443 }, 3444 3445 dispatchEvent: function dispatchEvent(event) { 3446 var type = event.type; 3447 var listeners = this.eventListeners && this.eventListeners[type] || []; 3448 3449 for (var i = 0; i < listeners.length; i++) { 3450 if (typeof listeners[i] == "function") { 3451 listeners[i].call(this, event); 3452 } else { 3453 listeners[i].handleEvent(event); 3454 } 3455 } 3456 3457 return !!event.defaultPrevented; 3458 } 3459 }; 3460}()); 3461 3462/** 3463 * @depend ../../sinon.js 3464 * @depend event.js 3465 */ 3466/*jslint eqeqeq: false, onevar: false*/ 3467/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ 3468/** 3469 * Fake XMLHttpRequest object 3470 * 3471 * @author Christian Johansen (christian@cjohansen.no) 3472 * @license BSD 3473 * 3474 * Copyright (c) 2010-2013 Christian Johansen 3475 */ 3476 3477// wrapper for global 3478(function(global) { 3479 if (typeof sinon === "undefined") { 3480 global.sinon = {}; 3481 } 3482 3483 var supportsProgress = typeof ProgressEvent !== "undefined"; 3484 var supportsCustomEvent = typeof CustomEvent !== "undefined"; 3485 sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest }; 3486 var xhr = sinon.xhr; 3487 xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; 3488 xhr.GlobalActiveXObject = global.ActiveXObject; 3489 xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; 3490 xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; 3491 xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX 3492 ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; 3493 xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest()); 3494 3495 /*jsl:ignore*/ 3496 var unsafeHeaders = { 3497 "Accept-Charset": true, 3498 "Accept-Encoding": true, 3499 "Connection": true, 3500 "Content-Length": true, 3501 "Cookie": true, 3502 "Cookie2": true, 3503 "Content-Transfer-Encoding": true, 3504 "Date": true, 3505 "Expect": true, 3506 "Host": true, 3507 "Keep-Alive": true, 3508 "Referer": true, 3509 "TE": true, 3510 "Trailer": true, 3511 "Transfer-Encoding": true, 3512 "Upgrade": true, 3513 "User-Agent": true, 3514 "Via": true 3515 }; 3516 /*jsl:end*/ 3517 3518 function FakeXMLHttpRequest() { 3519 this.readyState = FakeXMLHttpRequest.UNSENT; 3520 this.requestHeaders = {}; 3521 this.requestBody = null; 3522 this.status = 0; 3523 this.statusText = ""; 3524 this.upload = new UploadProgress(); 3525 if (sinon.xhr.supportsCORS) { 3526 this.withCredentials = false; 3527 } 3528 3529 3530 var xhr = this; 3531 var events = ["loadstart", "load", "abort", "loadend"]; 3532 3533 function addEventListener(eventName) { 3534 xhr.addEventListener(eventName, function (event) { 3535 var listener = xhr["on" + eventName]; 3536 3537 if (listener && typeof listener == "function") { 3538 listener.call(this, event); 3539 } 3540 }); 3541 } 3542 3543 for (var i = events.length - 1; i >= 0; i--) { 3544 addEventListener(events[i]); 3545 } 3546 3547 if (typeof FakeXMLHttpRequest.onCreate == "function") { 3548 FakeXMLHttpRequest.onCreate(this); 3549 } 3550 } 3551 3552 // An upload object is created for each 3553 // FakeXMLHttpRequest and allows upload 3554 // events to be simulated using uploadProgress 3555 // and uploadError. 3556 function UploadProgress() { 3557 this.eventListeners = { 3558 "progress": [], 3559 "load": [], 3560 "abort": [], 3561 "error": [] 3562 } 3563 } 3564 3565 UploadProgress.prototype.addEventListener = function(event, listener) { 3566 this.eventListeners[event].push(listener); 3567 }; 3568 3569 UploadProgress.prototype.removeEventListener = function(event, listener) { 3570 var listeners = this.eventListeners[event] || []; 3571 3572 for (var i = 0, l = listeners.length; i < l; ++i) { 3573 if (listeners[i] == listener) { 3574 return listeners.splice(i, 1); 3575 } 3576 } 3577 }; 3578 3579 UploadProgress.prototype.dispatchEvent = function(event) { 3580 var listeners = this.eventListeners[event.type] || []; 3581 3582 for (var i = 0, listener; (listener = listeners[i]) != null; i++) { 3583 listener(event); 3584 } 3585 }; 3586 3587 function verifyState(xhr) { 3588 if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { 3589 throw new Error("INVALID_STATE_ERR"); 3590 } 3591 3592 if (xhr.sendFlag) { 3593 throw new Error("INVALID_STATE_ERR"); 3594 } 3595 } 3596 3597 // filtering to enable a white-list version of Sinon FakeXhr, 3598 // where whitelisted requests are passed through to real XHR 3599 function each(collection, callback) { 3600 if (!collection) return; 3601 for (var i = 0, l = collection.length; i < l; i += 1) { 3602 callback(collection[i]); 3603 } 3604 } 3605 function some(collection, callback) { 3606 for (var index = 0; index < collection.length; index++) { 3607 if(callback(collection[index]) === true) return true; 3608 } 3609 return false; 3610 } 3611 // largest arity in XHR is 5 - XHR#open 3612 var apply = function(obj,method,args) { 3613 switch(args.length) { 3614 case 0: return obj[method](); 3615 case 1: return obj[method](args[0]); 3616 case 2: return obj[method](args[0],args[1]); 3617 case 3: return obj[method](args[0],args[1],args[2]); 3618 case 4: return obj[method](args[0],args[1],args[2],args[3]); 3619 case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); 3620 } 3621 }; 3622 3623 FakeXMLHttpRequest.filters = []; 3624 FakeXMLHttpRequest.addFilter = function(fn) { 3625 this.filters.push(fn) 3626 }; 3627 var IE6Re = /MSIE 6/; 3628 FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { 3629 var xhr = new sinon.xhr.workingXHR(); 3630 each(["open","setRequestHeader","send","abort","getResponseHeader", 3631 "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], 3632 function(method) { 3633 fakeXhr[method] = function() { 3634 return apply(xhr,method,arguments); 3635 }; 3636 }); 3637 3638 var copyAttrs = function(args) { 3639 each(args, function(attr) { 3640 try { 3641 fakeXhr[attr] = xhr[attr] 3642 } catch(e) { 3643 if(!IE6Re.test(navigator.userAgent)) throw e; 3644 } 3645 }); 3646 }; 3647 3648 var stateChange = function() { 3649 fakeXhr.readyState = xhr.readyState; 3650 if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { 3651 copyAttrs(["status","statusText"]); 3652 } 3653 if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { 3654 copyAttrs(["responseText"]); 3655 } 3656 if(xhr.readyState === FakeXMLHttpRequest.DONE) { 3657 copyAttrs(["responseXML"]); 3658 } 3659 if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); 3660 }; 3661 if(xhr.addEventListener) { 3662 for(var event in fakeXhr.eventListeners) { 3663 if(fakeXhr.eventListeners.hasOwnProperty(event)) { 3664 each(fakeXhr.eventListeners[event],function(handler) { 3665 xhr.addEventListener(event, handler); 3666 }); 3667 } 3668 } 3669 xhr.addEventListener("readystatechange",stateChange); 3670 } else { 3671 xhr.onreadystatechange = stateChange; 3672 } 3673 apply(xhr,"open",xhrArgs); 3674 }; 3675 FakeXMLHttpRequest.useFilters = false; 3676 3677 function verifyRequestOpened(xhr) { 3678 if (xhr.readyState != FakeXMLHttpRequest.OPENED) { 3679 throw new Error("INVALID_STATE_ERR - " + xhr.readyState); 3680 } 3681 } 3682 3683 function verifyRequestSent(xhr) { 3684 if (xhr.readyState == FakeXMLHttpRequest.DONE) { 3685 throw new Error("Request done"); 3686 } 3687 } 3688 3689 function verifyHeadersReceived(xhr) { 3690 if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { 3691 throw new Error("No headers received"); 3692 } 3693 } 3694 3695 function verifyResponseBodyType(body) { 3696 if (typeof body != "string") { 3697 var error = new Error("Attempted to respond to fake XMLHttpRequest with " + 3698 body + ", which is not a string."); 3699 error.name = "InvalidBodyException"; 3700 throw error; 3701 } 3702 } 3703 3704 sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { 3705 async: true, 3706 3707 open: function open(method, url, async, username, password) { 3708 this.method = method; 3709 this.url = url; 3710 this.async = typeof async == "boolean" ? async : true; 3711 this.username = username; 3712 this.password = password; 3713 this.responseText = null; 3714 this.responseXML = null; 3715 this.requestHeaders = {}; 3716 this.sendFlag = false; 3717 if(sinon.FakeXMLHttpRequest.useFilters === true) { 3718 var xhrArgs = arguments; 3719 var defake = some(FakeXMLHttpRequest.filters,function(filter) { 3720 return filter.apply(this,xhrArgs) 3721 }); 3722 if (defake) { 3723 return sinon.FakeXMLHttpRequest.defake(this,arguments); 3724 } 3725 } 3726 this.readyStateChange(FakeXMLHttpRequest.OPENED); 3727 }, 3728 3729 readyStateChange: function readyStateChange(state) { 3730 this.readyState = state; 3731 3732 if (typeof this.onreadystatechange == "function") { 3733 try { 3734 this.onreadystatechange(); 3735 } catch (e) { 3736 sinon.logError("Fake XHR onreadystatechange handler", e); 3737 } 3738 } 3739 3740 this.dispatchEvent(new sinon.Event("readystatechange")); 3741 3742 switch (this.readyState) { 3743 case FakeXMLHttpRequest.DONE: 3744 this.dispatchEvent(new sinon.Event("load", false, false, this)); 3745 this.dispatchEvent(new sinon.Event("loadend", false, false, this)); 3746 this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); 3747 if (supportsProgress) { 3748 this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100})); 3749 } 3750 break; 3751 } 3752 }, 3753 3754 setRequestHeader: function setRequestHeader(header, value) { 3755 verifyState(this); 3756 3757 if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { 3758 throw new Error("Refused to set unsafe header \"" + header + "\""); 3759 } 3760 3761 if (this.requestHeaders[header]) { 3762 this.requestHeaders[header] += "," + value; 3763 } else { 3764 this.requestHeaders[header] = value; 3765 } 3766 }, 3767 3768 // Helps testing 3769 setResponseHeaders: function setResponseHeaders(headers) { 3770 verifyRequestOpened(this); 3771 this.responseHeaders = {}; 3772 3773 for (var header in headers) { 3774 if (headers.hasOwnProperty(header)) { 3775 this.responseHeaders[header] = headers[header]; 3776 } 3777 } 3778 3779 if (this.async) { 3780 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); 3781 } else { 3782 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; 3783 } 3784 }, 3785 3786 // Currently treats ALL data as a DOMString (i.e. no Document) 3787 send: function send(data) { 3788 verifyState(this); 3789 3790 if (!/^(get|head)$/i.test(this.method)) { 3791 if (this.requestHeaders["Content-Type"]) { 3792 var value = this.requestHeaders["Content-Type"].split(";"); 3793 this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; 3794 } else { 3795 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; 3796 } 3797 3798 this.requestBody = data; 3799 } 3800 3801 this.errorFlag = false; 3802 this.sendFlag = this.async; 3803 this.readyStateChange(FakeXMLHttpRequest.OPENED); 3804 3805 if (typeof this.onSend == "function") { 3806 this.onSend(this); 3807 } 3808 3809 this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); 3810 }, 3811 3812 abort: function abort() { 3813 this.aborted = true; 3814 this.responseText = null; 3815 this.errorFlag = true; 3816 this.requestHeaders = {}; 3817 3818 if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { 3819 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); 3820 this.sendFlag = false; 3821 } 3822 3823 this.readyState = sinon.FakeXMLHttpRequest.UNSENT; 3824 3825 this.dispatchEvent(new sinon.Event("abort", false, false, this)); 3826 3827 this.upload.dispatchEvent(new sinon.Event("abort", false, false, this)); 3828 3829 if (typeof this.onerror === "function") { 3830 this.onerror(); 3831 } 3832 }, 3833 3834 getResponseHeader: function getResponseHeader(header) { 3835 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { 3836 return null; 3837 } 3838 3839 if (/^Set-Cookie2?$/i.test(header)) { 3840 return null; 3841 } 3842 3843 header = header.toLowerCase(); 3844 3845 for (var h in this.responseHeaders) { 3846 if (h.toLowerCase() == header) { 3847 return this.responseHeaders[h]; 3848 } 3849 } 3850 3851 return null; 3852 }, 3853 3854 getAllResponseHeaders: function getAllResponseHeaders() { 3855 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { 3856 return ""; 3857 } 3858 3859 var headers = ""; 3860 3861 for (var header in this.responseHeaders) { 3862 if (this.responseHeaders.hasOwnProperty(header) && 3863 !/^Set-Cookie2?$/i.test(header)) { 3864 headers += header + ": " + this.responseHeaders[header] + "\r\n"; 3865 } 3866 } 3867 3868 return headers; 3869 }, 3870 3871 setResponseBody: function setResponseBody(body) { 3872 verifyRequestSent(this); 3873 verifyHeadersReceived(this); 3874 verifyResponseBodyType(body); 3875 3876 var chunkSize = this.chunkSize || 10; 3877 var index = 0; 3878 this.responseText = ""; 3879 3880 do { 3881 if (this.async) { 3882 this.readyStateChange(FakeXMLHttpRequest.LOADING); 3883 } 3884 3885 this.responseText += body.substring(index, index + chunkSize); 3886 index += chunkSize; 3887 } while (index < body.length); 3888 3889 var type = this.getResponseHeader("Content-Type"); 3890 3891 if (this.responseText && 3892 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { 3893 try { 3894 this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); 3895 } catch (e) { 3896 // Unable to parse XML - no biggie 3897 } 3898 } 3899 3900 if (this.async) { 3901 this.readyStateChange(FakeXMLHttpRequest.DONE); 3902 } else { 3903 this.readyState = FakeXMLHttpRequest.DONE; 3904 } 3905 }, 3906 3907 respond: function respond(status, headers, body) { 3908 this.status = typeof status == "number" ? status : 200; 3909 this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; 3910 this.setResponseHeaders(headers || {}); 3911 this.setResponseBody(body || ""); 3912 }, 3913 3914 uploadProgress: function uploadProgress(progressEventRaw) { 3915 if (supportsProgress) { 3916 this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); 3917 } 3918 }, 3919 3920 uploadError: function uploadError(error) { 3921 if (supportsCustomEvent) { 3922 this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error})); 3923 } 3924 } 3925 }); 3926 3927 sinon.extend(FakeXMLHttpRequest, { 3928 UNSENT: 0, 3929 OPENED: 1, 3930 HEADERS_RECEIVED: 2, 3931 LOADING: 3, 3932 DONE: 4 3933 }); 3934 3935 // Borrowed from JSpec 3936 FakeXMLHttpRequest.parseXML = function parseXML(text) { 3937 var xmlDoc; 3938 3939 if (typeof DOMParser != "undefined") { 3940 var parser = new DOMParser(); 3941 xmlDoc = parser.parseFromString(text, "text/xml"); 3942 } else { 3943 xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 3944 xmlDoc.async = "false"; 3945 xmlDoc.loadXML(text); 3946 } 3947 3948 return xmlDoc; 3949 }; 3950 3951 FakeXMLHttpRequest.statusCodes = { 3952 100: "Continue", 3953 101: "Switching Protocols", 3954 200: "OK", 3955 201: "Created", 3956 202: "Accepted", 3957 203: "Non-Authoritative Information", 3958 204: "No Content", 3959 205: "Reset Content", 3960 206: "Partial Content", 3961 300: "Multiple Choice", 3962 301: "Moved Permanently", 3963 302: "Found", 3964 303: "See Other", 3965 304: "Not Modified", 3966 305: "Use Proxy", 3967 307: "Temporary Redirect", 3968 400: "Bad Request", 3969 401: "Unauthorized", 3970 402: "Payment Required", 3971 403: "Forbidden", 3972 404: "Not Found", 3973 405: "Method Not Allowed", 3974 406: "Not Acceptable", 3975 407: "Proxy Authentication Required", 3976 408: "Request Timeout", 3977 409: "Conflict", 3978 410: "Gone", 3979 411: "Length Required", 3980 412: "Precondition Failed", 3981 413: "Request Entity Too Large", 3982 414: "Request-URI Too Long", 3983 415: "Unsupported Media Type", 3984 416: "Requested Range Not Satisfiable", 3985 417: "Expectation Failed", 3986 422: "Unprocessable Entity", 3987 500: "Internal Server Error", 3988 501: "Not Implemented", 3989 502: "Bad Gateway", 3990 503: "Service Unavailable", 3991 504: "Gateway Timeout", 3992 505: "HTTP Version Not Supported" 3993 }; 3994 3995 sinon.useFakeXMLHttpRequest = function () { 3996 sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { 3997 if (xhr.supportsXHR) { 3998 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; 3999 } 4000 4001 if (xhr.supportsActiveX) { 4002 global.ActiveXObject = xhr.GlobalActiveXObject; 4003 } 4004 4005 delete sinon.FakeXMLHttpRequest.restore; 4006 4007 if (keepOnCreate !== true) { 4008 delete sinon.FakeXMLHttpRequest.onCreate; 4009 } 4010 }; 4011 if (xhr.supportsXHR) { 4012 global.XMLHttpRequest = sinon.FakeXMLHttpRequest; 4013 } 4014 4015 if (xhr.supportsActiveX) { 4016 global.ActiveXObject = function ActiveXObject(objId) { 4017 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { 4018 4019 return new sinon.FakeXMLHttpRequest(); 4020 } 4021 4022 return new xhr.GlobalActiveXObject(objId); 4023 }; 4024 } 4025 4026 return sinon.FakeXMLHttpRequest; 4027 }; 4028 4029 sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; 4030 4031})(typeof global === "object" ? global : this); 4032 4033if (typeof module !== 'undefined' && module.exports) { 4034 module.exports = sinon; 4035} 4036 4037/** 4038 * @depend fake_xml_http_request.js 4039 */ 4040/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ 4041/*global module, require, window*/ 4042/** 4043 * The Sinon "server" mimics a web server that receives requests from 4044 * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, 4045 * both synchronously and asynchronously. To respond synchronuously, canned 4046 * answers have to be provided upfront. 4047 * 4048 * @author Christian Johansen (christian@cjohansen.no) 4049 * @license BSD 4050 * 4051 * Copyright (c) 2010-2013 Christian Johansen 4052 */ 4053 4054if (typeof sinon == "undefined") { 4055 var sinon = {}; 4056} 4057 4058sinon.fakeServer = (function () { 4059 var push = [].push; 4060 function F() {} 4061 4062 function create(proto) { 4063 F.prototype = proto; 4064 return new F(); 4065 } 4066 4067 function responseArray(handler) { 4068 var response = handler; 4069 4070 if (Object.prototype.toString.call(handler) != "[object Array]") { 4071 response = [200, {}, handler]; 4072 } 4073 4074 if (typeof response[2] != "string") { 4075 throw new TypeError("Fake server response body should be string, but was " + 4076 typeof response[2]); 4077 } 4078 4079 return response; 4080 } 4081 4082 var wloc = typeof window !== "undefined" ? window.location : {}; 4083 var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); 4084 4085 function matchOne(response, reqMethod, reqUrl) { 4086 var rmeth = response.method; 4087 var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); 4088 var url = response.url; 4089 var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); 4090 4091 return matchMethod && matchUrl; 4092 } 4093 4094 function match(response, request) { 4095 var requestUrl = request.url; 4096 4097 if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { 4098 requestUrl = requestUrl.replace(rCurrLoc, ""); 4099 } 4100 4101 if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { 4102 if (typeof response.response == "function") { 4103 var ru = response.url; 4104 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); 4105 return response.response.apply(response, args); 4106 } 4107 4108 return true; 4109 } 4110 4111 return false; 4112 } 4113 4114 function log(response, request) { 4115 var str; 4116 4117 str = "Request:\n" + sinon.format(request) + "\n\n"; 4118 str += "Response:\n" + sinon.format(response) + "\n\n"; 4119 4120 sinon.log(str); 4121 } 4122 4123 return { 4124 create: function () { 4125 var server = create(this); 4126 this.xhr = sinon.useFakeXMLHttpRequest(); 4127 server.requests = []; 4128 4129 this.xhr.onCreate = function (xhrObj) { 4130 server.addRequest(xhrObj); 4131 }; 4132 4133 return server; 4134 }, 4135 4136 addRequest: function addRequest(xhrObj) { 4137 var server = this; 4138 push.call(this.requests, xhrObj); 4139 4140 xhrObj.onSend = function () { 4141 server.handleRequest(this); 4142 4143 if (server.autoRespond && !server.responding) { 4144 setTimeout(function () { 4145 server.responding = false; 4146 server.respond(); 4147 }, server.autoRespondAfter || 10); 4148 4149 server.responding = true; 4150 } 4151 }; 4152 }, 4153 4154 getHTTPMethod: function getHTTPMethod(request) { 4155 if (this.fakeHTTPMethods && /post/i.test(request.method)) { 4156 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); 4157 return !!matches ? matches[1] : request.method; 4158 } 4159 4160 return request.method; 4161 }, 4162 4163 handleRequest: function handleRequest(xhr) { 4164 if (xhr.async) { 4165 if (!this.queue) { 4166 this.queue = []; 4167 } 4168 4169 push.call(this.queue, xhr); 4170 } else { 4171 this.processRequest(xhr); 4172 } 4173 }, 4174 4175 respondWith: function respondWith(method, url, body) { 4176 if (arguments.length == 1 && typeof method != "function") { 4177 this.response = responseArray(method); 4178 return; 4179 } 4180 4181 if (!this.responses) { this.responses = []; } 4182 4183 if (arguments.length == 1) { 4184 body = method; 4185 url = method = null; 4186 } 4187 4188 if (arguments.length == 2) { 4189 body = url; 4190 url = method; 4191 method = null; 4192 } 4193 4194 push.call(this.responses, { 4195 method: method, 4196 url: url, 4197 response: typeof body == "function" ? body : responseArray(body) 4198 }); 4199 }, 4200 4201 respond: function respond() { 4202 if (arguments.length > 0) this.respondWith.apply(this, arguments); 4203 var queue = this.queue || []; 4204 var requests = queue.splice(0, queue.length); 4205 var request; 4206 4207 while(request = requests.shift()) { 4208 this.processRequest(request); 4209 } 4210 }, 4211 4212 processRequest: function processRequest(request) { 4213 try { 4214 if (request.aborted) { 4215 return; 4216 } 4217 4218 var response = this.response || [404, {}, ""]; 4219 4220 if (this.responses) { 4221 for (var l = this.responses.length, i = l - 1; i >= 0; i--) { 4222 if (match.call(this, this.responses[i], request)) { 4223 response = this.responses[i].response; 4224 break; 4225 } 4226 } 4227 } 4228 4229 if (request.readyState != 4) { 4230 log(response, request); 4231 4232 request.respond(response[0], response[1], response[2]); 4233 } 4234 } catch (e) { 4235 sinon.logError("Fake server request processing", e); 4236 } 4237 }, 4238 4239 restore: function restore() { 4240 return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); 4241 } 4242 }; 4243}()); 4244 4245if (typeof module !== 'undefined' && module.exports) { 4246 module.exports = sinon; 4247} 4248 4249/** 4250 * @depend fake_server.js 4251 * @depend fake_timers.js 4252 */ 4253/*jslint browser: true, eqeqeq: false, onevar: false*/ 4254/*global sinon*/ 4255/** 4256 * Add-on for sinon.fakeServer that automatically handles a fake timer along with 4257 * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery 4258 * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, 4259 * it polls the object for completion with setInterval. Dispite the direct 4260 * motivation, there is nothing jQuery-specific in this file, so it can be used 4261 * in any environment where the ajax implementation depends on setInterval or 4262 * setTimeout. 4263 * 4264 * @author Christian Johansen (christian@cjohansen.no) 4265 * @license BSD 4266 * 4267 * Copyright (c) 2010-2013 Christian Johansen 4268 */ 4269 4270(function () { 4271 function Server() {} 4272 Server.prototype = sinon.fakeServer; 4273 4274 sinon.fakeServerWithClock = new Server(); 4275 4276 sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { 4277 if (xhr.async) { 4278 if (typeof setTimeout.clock == "object") { 4279 this.clock = setTimeout.clock; 4280 } else { 4281 this.clock = sinon.useFakeTimers(); 4282 this.resetClock = true; 4283 } 4284 4285 if (!this.longestTimeout) { 4286 var clockSetTimeout = this.clock.setTimeout; 4287 var clockSetInterval = this.clock.setInterval; 4288 var server = this; 4289 4290 this.clock.setTimeout = function (fn, timeout) { 4291 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); 4292 4293 return clockSetTimeout.apply(this, arguments); 4294 }; 4295 4296 this.clock.setInterval = function (fn, timeout) { 4297 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); 4298 4299 return clockSetInterval.apply(this, arguments); 4300 }; 4301 } 4302 } 4303 4304 return sinon.fakeServer.addRequest.call(this, xhr); 4305 }; 4306 4307 sinon.fakeServerWithClock.respond = function respond() { 4308 var returnVal = sinon.fakeServer.respond.apply(this, arguments); 4309 4310 if (this.clock) { 4311 this.clock.tick(this.longestTimeout || 0); 4312 this.longestTimeout = 0; 4313 4314 if (this.resetClock) { 4315 this.clock.restore(); 4316 this.resetClock = false; 4317 } 4318 } 4319 4320 return returnVal; 4321 }; 4322 4323 sinon.fakeServerWithClock.restore = function restore() { 4324 if (this.clock) { 4325 this.clock.restore(); 4326 } 4327 4328 return sinon.fakeServer.restore.apply(this, arguments); 4329 }; 4330}()); 4331 4332/** 4333 * @depend ../sinon.js 4334 * @depend collection.js 4335 * @depend util/fake_timers.js 4336 * @depend util/fake_server_with_clock.js 4337 */ 4338/*jslint eqeqeq: false, onevar: false, plusplus: false*/ 4339/*global require, module*/ 4340/** 4341 * Manages fake collections as well as fake utilities such as Sinon's 4342 * timers and fake XHR implementation in one convenient object. 4343 * 4344 * @author Christian Johansen (christian@cjohansen.no) 4345 * @license BSD 4346 * 4347 * Copyright (c) 2010-2013 Christian Johansen 4348 */ 4349 4350if (typeof module !== "undefined" && module.exports && typeof require == "function") { 4351 var sinon = require("../sinon"); 4352 sinon.extend(sinon, require("./util/fake_timers")); 4353} 4354 4355(function () { 4356 var push = [].push; 4357 4358 function exposeValue(sandbox, config, key, value) { 4359 if (!value) { 4360 return; 4361 } 4362 4363 if (config.injectInto && !(key in config.injectInto)) { 4364 config.injectInto[key] = value; 4365 sandbox.injectedKeys.push(key); 4366 } else { 4367 push.call(sandbox.args, value); 4368 } 4369 } 4370 4371 function prepareSandboxFromConfig(config) { 4372 var sandbox = sinon.create(sinon.sandbox); 4373 4374 if (config.useFakeServer) { 4375 if (typeof config.useFakeServer == "object") { 4376 sandbox.serverPrototype = config.useFakeServer; 4377 } 4378 4379 sandbox.useFakeServer(); 4380 } 4381 4382 if (config.useFakeTimers) { 4383 if (typeof config.useFakeTimers == "object") { 4384 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); 4385 } else { 4386 sandbox.useFakeTimers(); 4387 } 4388 } 4389 4390 return sandbox; 4391 } 4392 4393 sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { 4394 useFakeTimers: function useFakeTimers() { 4395 this.clock = sinon.useFakeTimers.apply(sinon, arguments); 4396 4397 return this.add(this.clock); 4398 }, 4399 4400 serverPrototype: sinon.fakeServer, 4401 4402 useFakeServer: function useFakeServer() { 4403 var proto = this.serverPrototype || sinon.fakeServer; 4404 4405 if (!proto || !proto.create) { 4406 return null; 4407 } 4408 4409 this.server = proto.create(); 4410 return this.add(this.server); 4411 }, 4412 4413 inject: function (obj) { 4414 sinon.collection.inject.call(this, obj); 4415 4416 if (this.clock) { 4417 obj.clock = this.clock; 4418 } 4419 4420 if (this.server) { 4421 obj.server = this.server; 4422 obj.requests = this.server.requests; 4423 } 4424 4425 return obj; 4426 }, 4427 4428 restore: function () { 4429 sinon.collection.restore.apply(this, arguments); 4430 this.restoreContext(); 4431 }, 4432 4433 restoreContext: function () { 4434 if (this.injectedKeys) { 4435 for (var i = 0, j = this.injectedKeys.length; i < j; i++) { 4436 delete this.injectInto[this.injectedKeys[i]]; 4437 } 4438 this.injectedKeys = []; 4439 } 4440 }, 4441 4442 create: function (config) { 4443 if (!config) { 4444 return sinon.create(sinon.sandbox); 4445 } 4446 4447 var sandbox = prepareSandboxFromConfig(config); 4448 sandbox.args = sandbox.args || []; 4449 sandbox.injectedKeys = []; 4450 sandbox.injectInto = config.injectInto; 4451 var prop, value, exposed = sandbox.inject({}); 4452 4453 if (config.properties) { 4454 for (var i = 0, l = config.properties.length; i < l; i++) { 4455 prop = config.properties[i]; 4456 value = exposed[prop] || prop == "sandbox" && sandbox; 4457 exposeValue(sandbox, config, prop, value); 4458 } 4459 } else { 4460 exposeValue(sandbox, config, "sandbox", value); 4461 } 4462 4463 return sandbox; 4464 } 4465 }); 4466 4467 sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; 4468 4469 if (typeof define === "function" && define.amd) { 4470 define(["module"], function(module) { module.exports = sinon.sandbox; }); 4471 } else if (typeof module !== 'undefined' && module.exports) { 4472 module.exports = sinon.sandbox; 4473 } 4474}()); 4475 4476/** 4477 * @depend ../sinon.js 4478 * @depend stub.js 4479 * @depend mock.js 4480 * @depend sandbox.js 4481 */ 4482/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ 4483/*global module, require, sinon*/ 4484/** 4485 * Test function, sandboxes fakes 4486 * 4487 * @author Christian Johansen (christian@cjohansen.no) 4488 * @license BSD 4489 * 4490 * Copyright (c) 2010-2013 Christian Johansen 4491 */ 4492 4493(function (sinon) { 4494 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 4495 4496 if (!sinon && commonJSModule) { 4497 sinon = require("../sinon"); 4498 } 4499 4500 if (!sinon) { 4501 return; 4502 } 4503 4504 function test(callback) { 4505 var type = typeof callback; 4506 4507 if (type != "function") { 4508 throw new TypeError("sinon.test needs to wrap a test function, got " + type); 4509 } 4510 4511 return function () { 4512 var config = sinon.getConfig(sinon.config); 4513 config.injectInto = config.injectIntoThis && this || config.injectInto; 4514 var sandbox = sinon.sandbox.create(config); 4515 var exception, result; 4516 var args = Array.prototype.slice.call(arguments).concat(sandbox.args); 4517 4518 try { 4519 result = callback.apply(this, args); 4520 } catch (e) { 4521 exception = e; 4522 } 4523 4524 if (typeof exception !== "undefined") { 4525 sandbox.restore(); 4526 throw exception; 4527 } 4528 else { 4529 sandbox.verifyAndRestore(); 4530 } 4531 4532 return result; 4533 }; 4534 } 4535 4536 test.config = { 4537 injectIntoThis: true, 4538 injectInto: null, 4539 properties: ["spy", "stub", "mock", "clock", "server", "requests"], 4540 useFakeTimers: true, 4541 useFakeServer: true 4542 }; 4543 4544 sinon.test = test; 4545 4546 if (typeof define === "function" && define.amd) { 4547 define(["module"], function(module) { module.exports = test; }); 4548 } else if (commonJSModule) { 4549 module.exports = test; 4550 } 4551}(typeof sinon == "object" && sinon || null)); 4552 4553/** 4554 * @depend ../sinon.js 4555 * @depend test.js 4556 */ 4557/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ 4558/*global module, require, sinon*/ 4559/** 4560 * Test case, sandboxes all test functions 4561 * 4562 * @author Christian Johansen (christian@cjohansen.no) 4563 * @license BSD 4564 * 4565 * Copyright (c) 2010-2013 Christian Johansen 4566 */ 4567 4568(function (sinon) { 4569 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 4570 4571 if (!sinon && commonJSModule) { 4572 sinon = require("../sinon"); 4573 } 4574 4575 if (!sinon || !Object.prototype.hasOwnProperty) { 4576 return; 4577 } 4578 4579 function createTest(property, setUp, tearDown) { 4580 return function () { 4581 if (setUp) { 4582 setUp.apply(this, arguments); 4583 } 4584 4585 var exception, result; 4586 4587 try { 4588 result = property.apply(this, arguments); 4589 } catch (e) { 4590 exception = e; 4591 } 4592 4593 if (tearDown) { 4594 tearDown.apply(this, arguments); 4595 } 4596 4597 if (exception) { 4598 throw exception; 4599 } 4600 4601 return result; 4602 }; 4603 } 4604 4605 function testCase(tests, prefix) { 4606 /*jsl:ignore*/ 4607 if (!tests || typeof tests != "object") { 4608 throw new TypeError("sinon.testCase needs an object with test functions"); 4609 } 4610 /*jsl:end*/ 4611 4612 prefix = prefix || "test"; 4613 var rPrefix = new RegExp("^" + prefix); 4614 var methods = {}, testName, property, method; 4615 var setUp = tests.setUp; 4616 var tearDown = tests.tearDown; 4617 4618 for (testName in tests) { 4619 if (tests.hasOwnProperty(testName)) { 4620 property = tests[testName]; 4621 4622 if (/^(setUp|tearDown)$/.test(testName)) { 4623 continue; 4624 } 4625 4626 if (typeof property == "function" && rPrefix.test(testName)) { 4627 method = property; 4628 4629 if (setUp || tearDown) { 4630 method = createTest(property, setUp, tearDown); 4631 } 4632 4633 methods[testName] = sinon.test(method); 4634 } else { 4635 methods[testName] = tests[testName]; 4636 } 4637 } 4638 } 4639 4640 return methods; 4641 } 4642 4643 sinon.testCase = testCase; 4644 4645 if (typeof define === "function" && define.amd) { 4646 define(["module"], function(module) { module.exports = testCase; }); 4647 } else if (commonJSModule) { 4648 module.exports = testCase; 4649 } 4650}(typeof sinon == "object" && sinon || null)); 4651 4652/** 4653 * @depend ../sinon.js 4654 * @depend stub.js 4655 */ 4656/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ 4657/*global module, require, sinon*/ 4658/** 4659 * Assertions matching the test spy retrieval interface. 4660 * 4661 * @author Christian Johansen (christian@cjohansen.no) 4662 * @license BSD 4663 * 4664 * Copyright (c) 2010-2013 Christian Johansen 4665 */ 4666 4667(function (sinon, global) { 4668 var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function"; 4669 var slice = Array.prototype.slice; 4670 var assert; 4671 4672 if (!sinon && commonJSModule) { 4673 sinon = require("../sinon"); 4674 } 4675 4676 if (!sinon) { 4677 return; 4678 } 4679 4680 function verifyIsStub() { 4681 var method; 4682 4683 for (var i = 0, l = arguments.length; i < l; ++i) { 4684 method = arguments[i]; 4685 4686 if (!method) { 4687 assert.fail("fake is not a spy"); 4688 } 4689 4690 if (typeof method != "function") { 4691 assert.fail(method + " is not a function"); 4692 } 4693 4694 if (typeof method.getCall != "function") { 4695 assert.fail(method + " is not stubbed"); 4696 } 4697 } 4698 } 4699 4700 function failAssertion(object, msg) { 4701 object = object || global; 4702 var failMethod = object.fail || assert.fail; 4703 failMethod.call(object, msg); 4704 } 4705 4706 function mirrorPropAsAssertion(name, method, message) { 4707 if (arguments.length == 2) { 4708 message = method; 4709 method = name; 4710 } 4711 4712 assert[name] = function (fake) { 4713 verifyIsStub(fake); 4714 4715 var args = slice.call(arguments, 1); 4716 var failed = false; 4717 4718 if (typeof method == "function") { 4719 failed = !method(fake); 4720 } else { 4721 failed = typeof fake[method] == "function" ? 4722 !fake[method].apply(fake, args) : !fake[method]; 4723 } 4724 4725 if (failed) { 4726 failAssertion(this, fake.printf.apply(fake, [message].concat(args))); 4727 } else { 4728 assert.pass(name); 4729 } 4730 }; 4731 } 4732 4733 function exposedName(prefix, prop) { 4734 return !prefix || /^fail/.test(prop) ? prop : 4735 prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); 4736 } 4737 4738 assert = { 4739 failException: "AssertError", 4740 4741 fail: function fail(message) { 4742 var error = new Error(message); 4743 error.name = this.failException || assert.failException; 4744 4745 throw error; 4746 }, 4747 4748 pass: function pass(assertion) {}, 4749 4750 callOrder: function assertCallOrder() { 4751 verifyIsStub.apply(null, arguments); 4752 var expected = "", actual = ""; 4753 4754 if (!sinon.calledInOrder(arguments)) { 4755 try { 4756 expected = [].join.call(arguments, ", "); 4757 var calls = slice.call(arguments); 4758 var i = calls.length; 4759 while (i) { 4760 if (!calls[--i].called) { 4761 calls.splice(i, 1); 4762 } 4763 } 4764 actual = sinon.orderByFirstCall(calls).join(", "); 4765 } catch (e) { 4766 // If this fails, we'll just fall back to the blank string 4767 } 4768 4769 failAssertion(this, "expected " + expected + " to be " + 4770 "called in order but were called as " + actual); 4771 } else { 4772 assert.pass("callOrder"); 4773 } 4774 }, 4775 4776 callCount: function assertCallCount(method, count) { 4777 verifyIsStub(method); 4778 4779 if (method.callCount != count) { 4780 var msg = "expected %n to be called " + sinon.timesInWords(count) + 4781 " but was called %c%C"; 4782 failAssertion(this, method.printf(msg)); 4783 } else { 4784 assert.pass("callCount"); 4785 } 4786 }, 4787 4788 expose: function expose(target, options) { 4789 if (!target) { 4790 throw new TypeError("target is null or undefined"); 4791 } 4792 4793 var o = options || {}; 4794 var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; 4795 var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; 4796 4797 for (var method in this) { 4798 if (method != "export" && (includeFail || !/^(fail)/.test(method))) { 4799 target[exposedName(prefix, method)] = this[method]; 4800 } 4801 } 4802 4803 return target; 4804 }, 4805 4806 match: function match(actual, expectation) { 4807 var matcher = sinon.match(expectation); 4808 if (matcher.test(actual)) { 4809 assert.pass("match"); 4810 } else { 4811 var formatted = [ 4812 "expected value to match", 4813 " expected = " + sinon.format(expectation), 4814 " actual = " + sinon.format(actual) 4815 ] 4816 failAssertion(this, formatted.join("\n")); 4817 } 4818 } 4819 }; 4820 4821 mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); 4822 mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, 4823 "expected %n to not have been called but was called %c%C"); 4824 mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); 4825 mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); 4826 mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); 4827 mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); 4828 mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); 4829 mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); 4830 mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); 4831 mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); 4832 mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); 4833 mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); 4834 mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); 4835 mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); 4836 mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); 4837 mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); 4838 mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); 4839 mirrorPropAsAssertion("threw", "%n did not throw exception%C"); 4840 mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); 4841 4842 sinon.assert = assert; 4843 4844 if (typeof define === "function" && define.amd) { 4845 define(["module"], function(module) { module.exports = assert; }); 4846 } else if (commonJSModule) { 4847 module.exports = assert; 4848 } 4849}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); 4850 4851/** 4852 * @depend ../../sinon.js 4853 * @depend event.js 4854 */ 4855/*jslint eqeqeq: false, onevar: false*/ 4856/*global sinon, module, require, XDomainRequest*/ 4857/** 4858 * Fake XDomainRequest object 4859 */ 4860"use strict"; 4861 4862if (typeof sinon == "undefined") { 4863 this.sinon = {}; 4864} 4865sinon.xdr = { XDomainRequest: this.XDomainRequest }; 4866 4867// wrapper for global 4868(function (global) { 4869 var xdr = sinon.xdr; 4870 xdr.GlobalXDomainRequest = global.XDomainRequest; 4871 xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; 4872 xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; 4873 4874 function FakeXDomainRequest() { 4875 this.readyState = FakeXDomainRequest.UNSENT; 4876 this.requestBody = null; 4877 this.requestHeaders = {}; 4878 this.status = 0; 4879 this.timeout = null; 4880 4881 if (typeof FakeXDomainRequest.onCreate == "function") { 4882 FakeXDomainRequest.onCreate(this); 4883 } 4884 } 4885 4886 function verifyState(xdr) { 4887 if (xdr.readyState !== FakeXDomainRequest.OPENED) { 4888 throw new Error("INVALID_STATE_ERR"); 4889 } 4890 4891 if (xdr.sendFlag) { 4892 throw new Error("INVALID_STATE_ERR"); 4893 } 4894 } 4895 4896 function verifyRequestSent(xdr) { 4897 if (xdr.readyState == FakeXDomainRequest.UNSENT) { 4898 throw new Error("Request not sent"); 4899 } 4900 if (xdr.readyState == FakeXDomainRequest.DONE) { 4901 throw new Error("Request done"); 4902 } 4903 } 4904 4905 function verifyResponseBodyType(body) { 4906 if (typeof body != "string") { 4907 var error = new Error("Attempted to respond to fake XDomainRequest with " + 4908 body + ", which is not a string."); 4909 error.name = "InvalidBodyException"; 4910 throw error; 4911 } 4912 } 4913 4914 sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { 4915 open: function open(method, url) { 4916 this.method = method; 4917 this.url = url; 4918 4919 this.responseText = null; 4920 this.sendFlag = false; 4921 4922 this.readyStateChange(FakeXDomainRequest.OPENED); 4923 }, 4924 4925 readyStateChange: function readyStateChange(state) { 4926 this.readyState = state; 4927 var eventName = ''; 4928 switch (this.readyState) { 4929 case FakeXDomainRequest.UNSENT: 4930 break; 4931 case FakeXDomainRequest.OPENED: 4932 break; 4933 case FakeXDomainRequest.LOADING: 4934 if (this.sendFlag){ 4935 //raise the progress event 4936 eventName = 'onprogress'; 4937 } 4938 break; 4939 case FakeXDomainRequest.DONE: 4940 if (this.isTimeout){ 4941 eventName = 'ontimeout' 4942 } 4943 else if (this.errorFlag || (this.status < 200 || this.status > 299)) { 4944 eventName = 'onerror'; 4945 } 4946 else { 4947 eventName = 'onload' 4948 } 4949 break; 4950 } 4951 4952 // raising event (if defined) 4953 if (eventName) { 4954 if (typeof this[eventName] == "function") { 4955 try { 4956 this[eventName](); 4957 } catch (e) { 4958 sinon.logError("Fake XHR " + eventName + " handler", e); 4959 } 4960 } 4961 } 4962 }, 4963 4964 send: function send(data) { 4965 verifyState(this); 4966 4967 if (!/^(get|head)$/i.test(this.method)) { 4968 this.requestBody = data; 4969 } 4970 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; 4971 4972 this.errorFlag = false; 4973 this.sendFlag = true; 4974 this.readyStateChange(FakeXDomainRequest.OPENED); 4975 4976 if (typeof this.onSend == "function") { 4977 this.onSend(this); 4978 } 4979 }, 4980 4981 abort: function abort() { 4982 this.aborted = true; 4983 this.responseText = null; 4984 this.errorFlag = true; 4985 4986 if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { 4987 this.readyStateChange(sinon.FakeXDomainRequest.DONE); 4988 this.sendFlag = false; 4989 } 4990 }, 4991 4992 setResponseBody: function setResponseBody(body) { 4993 verifyRequestSent(this); 4994 verifyResponseBodyType(body); 4995 4996 var chunkSize = this.chunkSize || 10; 4997 var index = 0; 4998 this.responseText = ""; 4999 5000 do { 5001 this.readyStateChange(FakeXDomainRequest.LOADING); 5002 this.responseText += body.substring(index, index + chunkSize); 5003 index += chunkSize; 5004 } while (index < body.length); 5005 5006 this.readyStateChange(FakeXDomainRequest.DONE); 5007 }, 5008 5009 respond: function respond(status, contentType, body) { 5010 // content-type ignored, since XDomainRequest does not carry this 5011 // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease 5012 // test integration across browsers 5013 this.status = typeof status == "number" ? status : 200; 5014 this.setResponseBody(body || ""); 5015 }, 5016 5017 simulatetimeout: function(){ 5018 this.status = 0; 5019 this.isTimeout = true; 5020 // Access to this should actually throw an error 5021 this.responseText = undefined; 5022 this.readyStateChange(FakeXDomainRequest.DONE); 5023 } 5024 }); 5025 5026 sinon.extend(FakeXDomainRequest, { 5027 UNSENT: 0, 5028 OPENED: 1, 5029 LOADING: 3, 5030 DONE: 4 5031 }); 5032 5033 sinon.useFakeXDomainRequest = function () { 5034 sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { 5035 if (xdr.supportsXDR) { 5036 global.XDomainRequest = xdr.GlobalXDomainRequest; 5037 } 5038 5039 delete sinon.FakeXDomainRequest.restore; 5040 5041 if (keepOnCreate !== true) { 5042 delete sinon.FakeXDomainRequest.onCreate; 5043 } 5044 }; 5045 if (xdr.supportsXDR) { 5046 global.XDomainRequest = sinon.FakeXDomainRequest; 5047 } 5048 return sinon.FakeXDomainRequest; 5049 }; 5050 5051 sinon.FakeXDomainRequest = FakeXDomainRequest; 5052})(this); 5053 5054if (typeof module == "object" && typeof require == "function") { 5055 module.exports = sinon; 5056} 5057 5058return sinon;}.call(typeof window != 'undefined' && window || {})); 5059