├── .gitignore ├── bower.json ├── build.cmd ├── karma.conf.js ├── karma_runner.cmd ├── lib ├── overload.min.js └── overload.min.js.map ├── package.json ├── readme.md ├── source └── overload.js └── specs ├── libs ├── es5-shim.min.js ├── sinon-1.3.4.js └── sinon-ie-1.3.4.js ├── matchers.js ├── when_calling_overload.fallback.js ├── when_calling_overload.js ├── when_calling_overload.with.js ├── when_calling_overload_with_a_Boolean_type.js ├── when_calling_overload_with_a_Custom_type.js ├── when_calling_overload_with_a_Function_type.js ├── when_calling_overload_with_a_Number_type.js ├── when_calling_overload_with_a_String_type.js ├── when_calling_overload_with_an_Array_type.js ├── when_calling_overload_with_an_Object_type.js ├── when_calling_overload_with_empty_array.js ├── when_chaining_using_with.js └── when_no_match_is_found.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Overload", 3 | "version": "0.3.0", 4 | "main": "lib/overload.min.js", 5 | "ignore": [ 6 | "**/.*", 7 | "**/*.cmd", 8 | "/*.js", 9 | "node_modules", 10 | "bower_components", 11 | "specs", 12 | "tools" 13 | ], 14 | "_source": "git://github.com/mariusgundersen/Overload.git" 15 | } 16 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | node_modules\.bin\ccjs.cmd source\overload.js --create_source_map=lib\overload.min.js.map > lib\overload.min.js -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config){ 2 | config.set({ 3 | 4 | files: [ 5 | 'specs/libs/*.js', 6 | 'specs/matchers.js', 7 | 'specs/*.js', 8 | 'source/*.js' 9 | ], 10 | 11 | frameworks: [ 12 | 'jasmine' 13 | ], 14 | 15 | exclude: [ 16 | 17 | ], 18 | 19 | reporters: [ 20 | 'dots' 21 | ], 22 | 23 | autoWatch: true 24 | 25 | }); 26 | }; -------------------------------------------------------------------------------- /karma_runner.cmd: -------------------------------------------------------------------------------- 1 | node_modules\.bin\karma.cmd start --dots -------------------------------------------------------------------------------- /lib/overload.min.js: -------------------------------------------------------------------------------- 1 | (function(e,a){"function"===typeof define&&define.amd?define([],function(){return e.overload=a()}):"object"===typeof exports?module.exports=a():e.overload=a()})(this,function(){function e(a){return a.name||a.toString().match(/function\s+([^(]+)/)[1]}function a(a){var f={}.toString.call(a).match(/\s([a-zA-Z]+)/)[1];return"Object"==f?e(a.constructor):f}function h(){var g=[],f=function(){},c=function(){for(var d=0;d>>0;if("[object Function]"!=m(a))throw new TypeError; 3 | for(;c>>0,e=Array(c);if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g>>0,e=[];if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e>>0;if("[object Function]"!=m(a))throw new TypeError; 5 | if(!b&&1==arguments.length)throw new TypeError;var c=0,e;if(2<=arguments.length)e=arguments[1];else{do{if(c in d){e=d[c++];break}if(++c>=b)throw new TypeError;}while(1)}for(;c>>0;if("[object Function]"!=m(a))throw new TypeError;if(!b&&1==arguments.length)throw new TypeError;var c,b=b-1;if(2<=arguments.length)c=arguments[1];else{do{if(b in d){c=d[b--]; 6 | break}if(0>--b)throw new TypeError;}while(1)}do b in this&&(c=a.call(void 0,c,d[b],b,d));while(b--);return c};if(!Array.prototype.indexOf)Array.prototype.indexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=0;1>>0;if(!b)return-1;var c=b-1;1c?"-":9999=c?-4:-6);for(d=a.length;d--;)b=a[d],10>b&&(a[d]="0"+b);return c+"-"+a.slice(0,2).join("-")+"T"+a.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};if(!Date.now)Date.now=function(){return(new Date).getTime()};if(!Date.prototype.toJSON)Date.prototype.toJSON=function(){if("function"!=typeof this.toISOString)throw new TypeError;return this.toISOString()}; 14 | if(!Date.parse||864E13!==Date.parse("+275760-09-13T00:00:00.000Z"))Date=function(a){var d=function g(b,d,c,f,h,i,j){var k=arguments.length;return this instanceof a?(k=1==k&&""+b===b?new a(g.parse(b)):7<=k?new a(b,d,c,f,h,i,j):6<=k?new a(b,d,c,f,h,i):5<=k?new a(b,d,c,f,h):4<=k?new a(b,d,c,f):3<=k?new a(b,d,c):2<=k?new a(b,d):1<=k?new a(b):new a,k.constructor=g,k):a.apply(this,arguments)},b=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"), 15 | c;for(c in a)d[c]=a[c];d.now=a.now;d.UTC=a.UTC;d.prototype=a.prototype;d.prototype.constructor=d;d.parse=function(d){var c=b.exec(d);if(c){c.shift();for(var f=1;7>f;f++)c[f]=+(c[f]||(3>f?1:0)),1==f&&c[f]--;var h=+c.pop(),i=+c.pop(),j=c.pop(),f=0;if(j){if(23=h?(c[0]=h+400,a.UTC.apply(this,c)+f-126227808E5):a.UTC.apply(this,c)+f}return a.parse.apply(this,arguments)};return d}(Date);j="\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff"; 16 | if(!String.prototype.trim||j.trim()){j="["+j+"]";var A=RegExp("^"+j+j+"*"),B=RegExp(j+j+"*$");String.prototype.trim=function(){return(""+this).replace(A,"").replace(B,"")}}var v=function(a){a=+a;a!==a?a=0:0!==a&&a!==1/0&&a!==-(1/0)&&(a=(0 80 ? 247 | prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" : 248 | prefix + "{ " + pieces.join(", ") + " }"; 249 | }; 250 | 251 | ascii.element = function (element) { 252 | var tagName = element.tagName.toLowerCase(); 253 | var attrs = element.attributes, attribute, pairs = [], attrName; 254 | 255 | for (var i = 0, l = attrs.length; i < l; ++i) { 256 | attribute = attrs.item(i); 257 | attrName = attribute.nodeName.toLowerCase().replace("html:", ""); 258 | 259 | if (attrName == "contenteditable" && attribute.nodeValue == "inherit") { 260 | continue; 261 | } 262 | 263 | if (!!attribute.nodeValue) { 264 | pairs.push(attrName + "=\"" + attribute.nodeValue + "\""); 265 | } 266 | } 267 | 268 | var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); 269 | var content = element.innerHTML; 270 | 271 | if (content.length > 20) { 272 | content = content.substr(0, 20) + "[...]"; 273 | } 274 | 275 | var res = formatted + pairs.join(" ") + ">" + content + ""; 276 | 277 | return res.replace(/ contentEditable="inherit"/, ""); 278 | }; 279 | 280 | ascii.constructorName = function (object) { 281 | var name = buster.functionName(object && object.constructor); 282 | var excludes = this.excludeConstructors || buster.format.excludeConstructors || []; 283 | 284 | for (var i = 0, l = excludes.length; i < l; ++i) { 285 | if (typeof excludes[i] == "string" && excludes[i] == name) { 286 | return ""; 287 | } else if (excludes[i].test && excludes[i].test(name)) { 288 | return ""; 289 | } 290 | } 291 | 292 | return name; 293 | }; 294 | 295 | return ascii; 296 | }()); 297 | 298 | if (typeof module != "undefined") { 299 | module.exports = buster.format; 300 | } 301 | /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/ 302 | /*global module, require, __dirname, document*/ 303 | /** 304 | * Sinon core utilities. For internal use only. 305 | * 306 | * @author Christian Johansen (christian@cjohansen.no) 307 | * @license BSD 308 | * 309 | * Copyright (c) 2010-2011 Christian Johansen 310 | */ 311 | 312 | var sinon = (function (buster) { 313 | var div = typeof document != "undefined" && document.createElement("div"); 314 | var hasOwn = Object.prototype.hasOwnProperty; 315 | 316 | function isDOMNode(obj) { 317 | var success = false; 318 | 319 | try { 320 | obj.appendChild(div); 321 | success = div.parentNode == obj; 322 | } catch (e) { 323 | return false; 324 | } finally { 325 | try { 326 | obj.removeChild(div); 327 | } catch (e) { 328 | // Remove failed, not much we can do about that 329 | } 330 | } 331 | 332 | return success; 333 | } 334 | 335 | function isElement(obj) { 336 | return div && obj && obj.nodeType === 1 && isDOMNode(obj); 337 | } 338 | 339 | function isFunction(obj) { 340 | return !!(obj && obj.constructor && obj.call && obj.apply); 341 | } 342 | 343 | function mirrorProperties(target, source) { 344 | for (var prop in source) { 345 | if (!hasOwn.call(target, prop)) { 346 | target[prop] = source[prop]; 347 | } 348 | } 349 | } 350 | 351 | var sinon = { 352 | wrapMethod: function wrapMethod(object, property, method) { 353 | if (!object) { 354 | throw new TypeError("Should wrap property of object"); 355 | } 356 | 357 | if (typeof method != "function") { 358 | throw new TypeError("Method wrapper should be function"); 359 | } 360 | 361 | var wrappedMethod = object[property]; 362 | 363 | if (!isFunction(wrappedMethod)) { 364 | throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + 365 | property + " as function"); 366 | } 367 | 368 | if (wrappedMethod.restore && wrappedMethod.restore.sinon) { 369 | throw new TypeError("Attempted to wrap " + property + " which is already wrapped"); 370 | } 371 | 372 | if (wrappedMethod.calledBefore) { 373 | var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; 374 | throw new TypeError("Attempted to wrap " + property + " which is already " + verb); 375 | } 376 | 377 | // IE 8 does not support hasOwnProperty on the window object. 378 | var owned = hasOwn.call(object, property); 379 | object[property] = method; 380 | method.displayName = property; 381 | 382 | method.restore = function () { 383 | if(owned) { 384 | object[property] = wrappedMethod; 385 | } else { 386 | delete object[property]; 387 | } 388 | }; 389 | 390 | method.restore.sinon = true; 391 | mirrorProperties(method, wrappedMethod); 392 | 393 | return method; 394 | }, 395 | 396 | extend: function extend(target) { 397 | for (var i = 1, l = arguments.length; i < l; i += 1) { 398 | for (var prop in arguments[i]) { 399 | if (arguments[i].hasOwnProperty(prop)) { 400 | target[prop] = arguments[i][prop]; 401 | } 402 | 403 | // DONT ENUM bug, only care about toString 404 | if (arguments[i].hasOwnProperty("toString") && 405 | arguments[i].toString != target.toString) { 406 | target.toString = arguments[i].toString; 407 | } 408 | } 409 | } 410 | 411 | return target; 412 | }, 413 | 414 | create: function create(proto) { 415 | var F = function () {}; 416 | F.prototype = proto; 417 | return new F(); 418 | }, 419 | 420 | deepEqual: function deepEqual(a, b) { 421 | if (typeof a != "object" || typeof b != "object") { 422 | return a === b; 423 | } 424 | 425 | if (isElement(a) || isElement(b)) { 426 | return a === b; 427 | } 428 | 429 | if (a === b) { 430 | return true; 431 | } 432 | 433 | var aString = Object.prototype.toString.call(a); 434 | if (aString != Object.prototype.toString.call(b)) { 435 | return false; 436 | } 437 | 438 | if (aString == "[object Array]") { 439 | if (a.length !== b.length) { 440 | return false; 441 | } 442 | 443 | for (var i = 0, l = a.length; i < l; i += 1) { 444 | if (!deepEqual(a[i], b[i])) { 445 | return false; 446 | } 447 | } 448 | 449 | return true; 450 | } 451 | 452 | var prop, aLength = 0, bLength = 0; 453 | 454 | for (prop in a) { 455 | aLength += 1; 456 | 457 | if (!deepEqual(a[prop], b[prop])) { 458 | return false; 459 | } 460 | } 461 | 462 | for (prop in b) { 463 | bLength += 1; 464 | } 465 | 466 | if (aLength != bLength) { 467 | return false; 468 | } 469 | 470 | return true; 471 | }, 472 | 473 | functionName: function functionName(func) { 474 | var name = func.displayName || func.name; 475 | 476 | // Use function decomposition as a last resort to get function 477 | // name. Does not rely on function decomposition to work - if it 478 | // doesn't debugging will be slightly less informative 479 | // (i.e. toString will say 'spy' rather than 'myFunc'). 480 | if (!name) { 481 | var matches = func.toString().match(/function ([^\s\(]+)/); 482 | name = matches && matches[1]; 483 | } 484 | 485 | return name; 486 | }, 487 | 488 | functionToString: function toString() { 489 | if (this.getCall && this.callCount) { 490 | var thisValue, prop, i = this.callCount; 491 | 492 | while (i--) { 493 | thisValue = this.getCall(i).thisValue; 494 | 495 | for (prop in thisValue) { 496 | if (thisValue[prop] === this) { 497 | return prop; 498 | } 499 | } 500 | } 501 | } 502 | 503 | return this.displayName || "sinon fake"; 504 | }, 505 | 506 | getConfig: function (custom) { 507 | var config = {}; 508 | custom = custom || {}; 509 | var defaults = sinon.defaultConfig; 510 | 511 | for (var prop in defaults) { 512 | if (defaults.hasOwnProperty(prop)) { 513 | config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; 514 | } 515 | } 516 | 517 | return config; 518 | }, 519 | 520 | format: function (val) { 521 | return "" + val; 522 | }, 523 | 524 | defaultConfig: { 525 | injectIntoThis: true, 526 | injectInto: null, 527 | properties: ["spy", "stub", "mock", "clock", "server", "requests"], 528 | useFakeTimers: true, 529 | useFakeServer: true 530 | }, 531 | 532 | timesInWords: function timesInWords(count) { 533 | return count == 1 && "once" || 534 | count == 2 && "twice" || 535 | count == 3 && "thrice" || 536 | (count || 0) + " times"; 537 | }, 538 | 539 | calledInOrder: function (spies) { 540 | for (var i = 1, l = spies.length; i < l; i++) { 541 | if (!spies[i - 1].calledBefore(spies[i])) { 542 | return false; 543 | } 544 | } 545 | 546 | return true; 547 | }, 548 | 549 | orderByFirstCall: function (spies) { 550 | return spies.sort(function (a, b) { 551 | // uuid, won't ever be equal 552 | var aCall = a.getCall(0); 553 | var bCall = b.getCall(0); 554 | var aId = aCall && aCall.callId || -1; 555 | var bId = bCall && bCall.callId || -1; 556 | 557 | return aId < bId ? -1 : 1; 558 | }); 559 | }, 560 | 561 | log: function () {}, 562 | 563 | logError: function (label, err) { 564 | var msg = label + " threw exception: " 565 | sinon.log(msg + "[" + err.name + "] " + err.message); 566 | if (err.stack) { sinon.log(err.stack); } 567 | 568 | setTimeout(function () { 569 | err.message = msg + err.message; 570 | throw err; 571 | }, 0); 572 | } 573 | }; 574 | 575 | var isNode = typeof module == "object" && typeof require == "function"; 576 | 577 | if (isNode) { 578 | try { 579 | buster = { format: require("buster-format") }; 580 | } catch (e) {} 581 | module.exports = sinon; 582 | module.exports.spy = require("./sinon/spy"); 583 | module.exports.stub = require("./sinon/stub"); 584 | module.exports.mock = require("./sinon/mock"); 585 | module.exports.collection = require("./sinon/collection"); 586 | module.exports.assert = require("./sinon/assert"); 587 | module.exports.sandbox = require("./sinon/sandbox"); 588 | module.exports.test = require("./sinon/test"); 589 | module.exports.testCase = require("./sinon/test_case"); 590 | module.exports.assert = require("./sinon/assert"); 591 | } 592 | 593 | if (buster) { 594 | var formatter = sinon.create(buster.format); 595 | formatter.quoteStrings = false; 596 | sinon.format = function () { 597 | return formatter.ascii.apply(formatter, arguments); 598 | }; 599 | } else if (isNode) { 600 | try { 601 | var util = require("util"); 602 | sinon.format = function (value) { 603 | return typeof value == "object" ? util.inspect(value) : value; 604 | }; 605 | } catch (e) { 606 | /* Node, but no util module - would be very old, but better safe than 607 | sorry */ 608 | } 609 | } 610 | 611 | return sinon; 612 | }(typeof buster == "object" && buster)); 613 | 614 | /* @depend ../sinon.js */ 615 | /*jslint eqeqeq: false, onevar: false, plusplus: false*/ 616 | /*global module, require, sinon*/ 617 | /** 618 | * Spy functions 619 | * 620 | * @author Christian Johansen (christian@cjohansen.no) 621 | * @license BSD 622 | * 623 | * Copyright (c) 2010-2011 Christian Johansen 624 | */ 625 | 626 | (function (sinon) { 627 | var commonJSModule = typeof module == "object" && typeof require == "function"; 628 | var spyCall; 629 | var callId = 0; 630 | var push = [].push; 631 | var slice = Array.prototype.slice; 632 | 633 | if (!sinon && commonJSModule) { 634 | sinon = require("../sinon"); 635 | } 636 | 637 | if (!sinon) { 638 | return; 639 | } 640 | 641 | function spy(object, property) { 642 | if (!property && typeof object == "function") { 643 | return spy.create(object); 644 | } 645 | 646 | if (!object || !property) { 647 | return spy.create(function () {}); 648 | } 649 | 650 | var method = object[property]; 651 | return sinon.wrapMethod(object, property, spy.create(method)); 652 | } 653 | 654 | sinon.extend(spy, (function () { 655 | 656 | function delegateToCalls(api, method, matchAny, actual, notCalled) { 657 | api[method] = function () { 658 | if (!this.called) { 659 | if (notCalled) { 660 | return notCalled.apply(this, arguments); 661 | } 662 | return false; 663 | } 664 | 665 | var currentCall; 666 | var matches = 0; 667 | 668 | for (var i = 0, l = this.callCount; i < l; i += 1) { 669 | currentCall = this.getCall(i); 670 | 671 | if (currentCall[actual || method].apply(currentCall, arguments)) { 672 | matches += 1; 673 | 674 | if (matchAny) { 675 | return true; 676 | } 677 | } 678 | } 679 | 680 | return matches === this.callCount; 681 | }; 682 | } 683 | 684 | function matchingFake(fakes, args, strict) { 685 | if (!fakes) { 686 | return; 687 | } 688 | 689 | var alen = args.length; 690 | 691 | for (var i = 0, l = fakes.length; i < l; i++) { 692 | if (fakes[i].matches(args, strict)) { 693 | return fakes[i]; 694 | } 695 | } 696 | } 697 | 698 | function incrementCallCount() { 699 | this.called = true; 700 | this.callCount += 1; 701 | this.calledOnce = this.callCount == 1; 702 | this.calledTwice = this.callCount == 2; 703 | this.calledThrice = this.callCount == 3; 704 | } 705 | 706 | function createCallProperties() { 707 | this.firstCall = this.getCall(0); 708 | this.secondCall = this.getCall(1); 709 | this.thirdCall = this.getCall(2); 710 | this.lastCall = this.getCall(this.callCount - 1); 711 | } 712 | 713 | var uuid = 0; 714 | 715 | // Public API 716 | var spyApi = { 717 | reset: function () { 718 | this.called = false; 719 | this.calledOnce = false; 720 | this.calledTwice = false; 721 | this.calledThrice = false; 722 | this.callCount = 0; 723 | this.firstCall = null; 724 | this.secondCall = null; 725 | this.thirdCall = null; 726 | this.lastCall = null; 727 | this.args = []; 728 | this.returnValues = []; 729 | this.thisValues = []; 730 | this.exceptions = []; 731 | this.callIds = []; 732 | }, 733 | 734 | create: function create(func) { 735 | var name; 736 | 737 | if (typeof func != "function") { 738 | func = function () {}; 739 | } else { 740 | name = sinon.functionName(func); 741 | } 742 | 743 | function proxy() { 744 | return proxy.invoke(func, this, slice.call(arguments)); 745 | } 746 | 747 | sinon.extend(proxy, spy); 748 | delete proxy.create; 749 | sinon.extend(proxy, func); 750 | 751 | proxy.reset(); 752 | proxy.prototype = func.prototype; 753 | proxy.displayName = name || "spy"; 754 | proxy.toString = sinon.functionToString; 755 | proxy._create = sinon.spy.create; 756 | proxy.id = "spy#" + uuid++; 757 | 758 | return proxy; 759 | }, 760 | 761 | invoke: function invoke(func, thisValue, args) { 762 | var matching = matchingFake(this.fakes, args); 763 | var exception, returnValue; 764 | 765 | incrementCallCount.call(this); 766 | push.call(this.thisValues, thisValue); 767 | push.call(this.args, args); 768 | push.call(this.callIds, callId++); 769 | 770 | try { 771 | if (matching) { 772 | returnValue = matching.invoke(func, thisValue, args); 773 | } else { 774 | returnValue = (this.func || func).apply(thisValue, args); 775 | } 776 | } catch (e) { 777 | push.call(this.returnValues, undefined); 778 | exception = e; 779 | throw e; 780 | } finally { 781 | push.call(this.exceptions, exception); 782 | } 783 | 784 | push.call(this.returnValues, returnValue); 785 | 786 | createCallProperties.call(this); 787 | 788 | return returnValue; 789 | }, 790 | 791 | getCall: function getCall(i) { 792 | if (i < 0 || i >= this.callCount) { 793 | return null; 794 | } 795 | 796 | return spyCall.create(this, this.thisValues[i], this.args[i], 797 | this.returnValues[i], this.exceptions[i], 798 | this.callIds[i]); 799 | }, 800 | 801 | calledBefore: function calledBefore(spyFn) { 802 | if (!this.called) { 803 | return false; 804 | } 805 | 806 | if (!spyFn.called) { 807 | return true; 808 | } 809 | 810 | return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; 811 | }, 812 | 813 | calledAfter: function calledAfter(spyFn) { 814 | if (!this.called || !spyFn.called) { 815 | return false; 816 | } 817 | 818 | return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; 819 | }, 820 | 821 | withArgs: function () { 822 | var args = slice.call(arguments); 823 | 824 | if (this.fakes) { 825 | var match = matchingFake(this.fakes, args, true); 826 | 827 | if (match) { 828 | return match; 829 | } 830 | } else { 831 | this.fakes = []; 832 | } 833 | 834 | var original = this; 835 | var fake = this._create(); 836 | fake.matchingAguments = args; 837 | push.call(this.fakes, fake); 838 | 839 | fake.withArgs = function () { 840 | return original.withArgs.apply(original, arguments); 841 | }; 842 | 843 | for (var i = 0; i < this.args.length; i++) { 844 | if (fake.matches(this.args[i])) { 845 | incrementCallCount.call(fake); 846 | push.call(fake.thisValues, this.thisValues[i]); 847 | push.call(fake.args, this.args[i]); 848 | push.call(fake.returnValues, this.returnValues[i]); 849 | push.call(fake.exceptions, this.exceptions[i]); 850 | push.call(fake.callIds, this.callIds[i]); 851 | } 852 | } 853 | createCallProperties.call(fake); 854 | 855 | return fake; 856 | }, 857 | 858 | matches: function (args, strict) { 859 | var margs = this.matchingAguments; 860 | 861 | if (margs.length <= args.length && 862 | sinon.deepEqual(margs, args.slice(0, margs.length))) { 863 | return !strict || margs.length == args.length; 864 | } 865 | }, 866 | 867 | printf: function (format) { 868 | var spy = this; 869 | var args = slice.call(arguments, 1); 870 | var formatter; 871 | 872 | return (format || "").replace(/%(.)/g, function (match, specifyer) { 873 | formatter = spyApi.formatters[specifyer]; 874 | 875 | if (typeof formatter == "function") { 876 | return formatter.call(null, spy, args); 877 | } else if (!isNaN(parseInt(specifyer), 10)) { 878 | return sinon.format(args[specifyer - 1]); 879 | } 880 | 881 | return "%" + specifyer; 882 | }); 883 | } 884 | }; 885 | 886 | delegateToCalls(spyApi, "calledOn", true); 887 | delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn"); 888 | delegateToCalls(spyApi, "calledWith", true); 889 | delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith"); 890 | delegateToCalls(spyApi, "calledWithExactly", true); 891 | delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly"); 892 | delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith", 893 | function () { return true; }); 894 | delegateToCalls(spyApi, "threw", true); 895 | delegateToCalls(spyApi, "alwaysThrew", false, "threw"); 896 | delegateToCalls(spyApi, "returned", true); 897 | delegateToCalls(spyApi, "alwaysReturned", false, "returned"); 898 | delegateToCalls(spyApi, "calledWithNew", true); 899 | delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew"); 900 | delegateToCalls(spyApi, "callArg", false, "callArgWith", function () { 901 | throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); 902 | }); 903 | spyApi.callArgWith = spyApi.callArg; 904 | delegateToCalls(spyApi, "yield", false, "yield", function () { 905 | throw new Error(this.toString() + " cannot yield since it was not yet invoked."); 906 | }); 907 | // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. 908 | spyApi.invokeCallback = spyApi.yield; 909 | delegateToCalls(spyApi, "yieldTo", false, "yieldTo", function (property) { 910 | throw new Error(this.toString() + " cannot yield to '" + property + 911 | "' since it was not yet invoked."); 912 | }); 913 | 914 | spyApi.formatters = { 915 | "c": function (spy) { 916 | return sinon.timesInWords(spy.callCount); 917 | }, 918 | 919 | "n": function (spy) { 920 | return spy.toString(); 921 | }, 922 | 923 | "C": function (spy) { 924 | var calls = []; 925 | 926 | for (var i = 0, l = spy.callCount; i < l; ++i) { 927 | push.call(calls, " " + spy.getCall(i).toString()); 928 | } 929 | 930 | return calls.length > 0 ? "\n" + calls.join("\n") : ""; 931 | }, 932 | 933 | "t": function (spy) { 934 | var objects = []; 935 | 936 | for (var i = 0, l = spy.callCount; i < l; ++i) { 937 | push.call(objects, sinon.format(spy.thisValues[i])); 938 | } 939 | 940 | return objects.join(", "); 941 | }, 942 | 943 | "*": function (spy, args) { 944 | return args.join(", "); 945 | } 946 | }; 947 | 948 | return spyApi; 949 | }())); 950 | 951 | spyCall = (function () { 952 | 953 | function throwYieldError(proxy, text, args) { 954 | var msg = sinon.functionName(proxy) + text; 955 | if (args.length) { 956 | msg += " Received [" + slice.call(args).join(", ") + "]"; 957 | } 958 | throw new Error(msg); 959 | } 960 | 961 | return { 962 | create: function create(spy, thisValue, args, returnValue, exception, id) { 963 | var proxyCall = sinon.create(spyCall); 964 | delete proxyCall.create; 965 | proxyCall.proxy = spy; 966 | proxyCall.thisValue = thisValue; 967 | proxyCall.args = args; 968 | proxyCall.returnValue = returnValue; 969 | proxyCall.exception = exception; 970 | proxyCall.callId = typeof id == "number" && id || callId++; 971 | 972 | return proxyCall; 973 | }, 974 | 975 | calledOn: function calledOn(thisValue) { 976 | return this.thisValue === thisValue; 977 | }, 978 | 979 | calledWith: function calledWith() { 980 | for (var i = 0, l = arguments.length; i < l; i += 1) { 981 | if (!sinon.deepEqual(arguments[i], this.args[i])) { 982 | return false; 983 | } 984 | } 985 | 986 | return true; 987 | }, 988 | 989 | calledWithExactly: function calledWithExactly() { 990 | return arguments.length == this.args.length && 991 | this.calledWith.apply(this, arguments); 992 | }, 993 | 994 | notCalledWith: function notCalledWith() { 995 | for (var i = 0, l = arguments.length; i < l; i += 1) { 996 | if (!sinon.deepEqual(arguments[i], this.args[i])) { 997 | return true; 998 | } 999 | } 1000 | return false; 1001 | }, 1002 | 1003 | returned: function returned(value) { 1004 | return this.returnValue === value; 1005 | }, 1006 | 1007 | threw: function threw(error) { 1008 | if (typeof error == "undefined" || !this.exception) { 1009 | return !!this.exception; 1010 | } 1011 | 1012 | if (typeof error == "string") { 1013 | return this.exception.name == error; 1014 | } 1015 | 1016 | return this.exception === error; 1017 | }, 1018 | 1019 | calledWithNew: function calledWithNew(thisValue) { 1020 | return this.thisValue instanceof this.proxy; 1021 | }, 1022 | 1023 | calledBefore: function (other) { 1024 | return this.callId < other.callId; 1025 | }, 1026 | 1027 | calledAfter: function (other) { 1028 | return this.callId > other.callId; 1029 | }, 1030 | 1031 | callArg: function (pos) { 1032 | this.args[pos](); 1033 | }, 1034 | 1035 | callArgWith: function (pos) { 1036 | var args = slice.call(arguments, 1); 1037 | this.args[pos].apply(null, args); 1038 | }, 1039 | 1040 | "yield": function () { 1041 | var args = this.args; 1042 | for (var i = 0, l = args.length; i < l; ++i) { 1043 | if (typeof args[i] === "function") { 1044 | args[i].apply(null, slice.call(arguments)); 1045 | return; 1046 | } 1047 | } 1048 | throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); 1049 | }, 1050 | 1051 | yieldTo: function (prop) { 1052 | var args = this.args; 1053 | for (var i = 0, l = args.length; i < l; ++i) { 1054 | if (args[i] && typeof args[i][prop] === "function") { 1055 | args[i][prop].apply(null, slice.call(arguments, 1)); 1056 | return; 1057 | } 1058 | } 1059 | throwYieldError(this.proxy, " cannot yield to '" + prop + 1060 | "' since no callback was passed.", args); 1061 | }, 1062 | 1063 | toString: function () { 1064 | var callStr = this.proxy.toString() + "("; 1065 | var args = []; 1066 | 1067 | for (var i = 0, l = this.args.length; i < l; ++i) { 1068 | push.call(args, sinon.format(this.args[i])); 1069 | } 1070 | 1071 | callStr = callStr + args.join(", ") + ")"; 1072 | 1073 | if (typeof this.returnValue != "undefined") { 1074 | callStr += " => " + sinon.format(this.returnValue); 1075 | } 1076 | 1077 | if (this.exception) { 1078 | callStr += " !" + this.exception.name; 1079 | 1080 | if (this.exception.message) { 1081 | callStr += "(" + this.exception.message + ")"; 1082 | } 1083 | } 1084 | 1085 | return callStr; 1086 | } 1087 | }; 1088 | }()); 1089 | 1090 | spy.spyCall = spyCall; 1091 | 1092 | // This steps outside the module sandbox and will be removed 1093 | sinon.spyCall = spyCall; 1094 | 1095 | if (commonJSModule) { 1096 | module.exports = spy; 1097 | } else { 1098 | sinon.spy = spy; 1099 | } 1100 | }(typeof sinon == "object" && sinon || null)); 1101 | 1102 | /** 1103 | * @depend ../sinon.js 1104 | * @depend spy.js 1105 | */ 1106 | /*jslint eqeqeq: false, onevar: false*/ 1107 | /*global module, require, sinon*/ 1108 | /** 1109 | * Stub functions 1110 | * 1111 | * @author Christian Johansen (christian@cjohansen.no) 1112 | * @license BSD 1113 | * 1114 | * Copyright (c) 2010-2011 Christian Johansen 1115 | */ 1116 | 1117 | (function (sinon) { 1118 | var commonJSModule = typeof module == "object" && typeof require == "function"; 1119 | 1120 | if (!sinon && commonJSModule) { 1121 | sinon = require("../sinon"); 1122 | } 1123 | 1124 | if (!sinon) { 1125 | return; 1126 | } 1127 | 1128 | function stub(object, property, func) { 1129 | if (!!func && typeof func != "function") { 1130 | throw new TypeError("Custom stub should be function"); 1131 | } 1132 | 1133 | var wrapper; 1134 | 1135 | if (func) { 1136 | wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; 1137 | } else { 1138 | wrapper = stub.create(); 1139 | } 1140 | 1141 | if (!object && !property) { 1142 | return sinon.stub.create(); 1143 | } 1144 | 1145 | if (!property && !!object && typeof object == "object") { 1146 | for (var prop in object) { 1147 | if (typeof object[prop] === "function") { 1148 | stub(object, prop); 1149 | } 1150 | } 1151 | 1152 | return object; 1153 | } 1154 | 1155 | return sinon.wrapMethod(object, property, wrapper); 1156 | } 1157 | 1158 | function getCallback(stub, args) { 1159 | if (stub.callArgAt < 0) { 1160 | for (var i = 0, l = args.length; i < l; ++i) { 1161 | if (!stub.callArgProp && typeof args[i] == "function") { 1162 | return args[i]; 1163 | } 1164 | 1165 | if (stub.callArgProp && args[i] && 1166 | typeof args[i][stub.callArgProp] == "function") { 1167 | return args[i][stub.callArgProp]; 1168 | } 1169 | } 1170 | 1171 | return null; 1172 | } 1173 | 1174 | return args[stub.callArgAt]; 1175 | } 1176 | 1177 | var join = Array.prototype.join; 1178 | 1179 | function getCallbackError(stub, func, args) { 1180 | if (stub.callArgAt < 0) { 1181 | var msg; 1182 | 1183 | if (stub.callArgProp) { 1184 | msg = sinon.functionName(stub) + 1185 | " expected to yield to '" + stub.callArgProp + 1186 | "', but no object with such a property was passed." 1187 | } else { 1188 | msg = sinon.functionName(stub) + 1189 | " expected to yield, but no callback was passed." 1190 | } 1191 | 1192 | if (args.length > 0) { 1193 | msg += " Received [" + join.call(args, ", ") + "]"; 1194 | } 1195 | 1196 | return msg; 1197 | } 1198 | 1199 | return "argument at index " + stub.callArgAt + " is not a function: " + func; 1200 | } 1201 | 1202 | function callCallback(stub, args) { 1203 | if (typeof stub.callArgAt == "number") { 1204 | var func = getCallback(stub, args); 1205 | 1206 | if (typeof func != "function") { 1207 | throw new TypeError(getCallbackError(stub, func, args)); 1208 | } 1209 | 1210 | func.apply(stub.callbackContext, stub.callbackArguments); 1211 | } 1212 | } 1213 | 1214 | var uuid = 0; 1215 | 1216 | sinon.extend(stub, (function () { 1217 | var slice = Array.prototype.slice; 1218 | 1219 | function throwsException(error, message) { 1220 | if (typeof error == "string") { 1221 | this.exception = new Error(message || ""); 1222 | this.exception.name = error; 1223 | } else if (!error) { 1224 | this.exception = new Error("Error"); 1225 | } else { 1226 | this.exception = error; 1227 | } 1228 | 1229 | return this; 1230 | } 1231 | 1232 | return { 1233 | create: function create() { 1234 | var functionStub = function () { 1235 | if (functionStub.exception) { 1236 | throw functionStub.exception; 1237 | } else if (typeof functionStub.returnArgAt == 'number') { 1238 | return arguments[functionStub.returnArgAt]; 1239 | } 1240 | 1241 | callCallback(functionStub, arguments); 1242 | 1243 | return functionStub.returnValue; 1244 | }; 1245 | 1246 | functionStub.id = "stub#" + uuid++; 1247 | var orig = functionStub; 1248 | functionStub = sinon.spy.create(functionStub); 1249 | functionStub.func = orig; 1250 | 1251 | sinon.extend(functionStub, stub); 1252 | functionStub._create = sinon.stub.create; 1253 | functionStub.displayName = "stub"; 1254 | functionStub.toString = sinon.functionToString; 1255 | 1256 | return functionStub; 1257 | }, 1258 | 1259 | returns: function returns(value) { 1260 | this.returnValue = value; 1261 | 1262 | return this; 1263 | }, 1264 | 1265 | returnsArg: function returnsArg(pos) { 1266 | if (typeof pos != "number") { 1267 | throw new TypeError("argument index is not number"); 1268 | } 1269 | 1270 | this.returnArgAt = pos; 1271 | 1272 | return this; 1273 | }, 1274 | 1275 | "throws": throwsException, 1276 | throwsException: throwsException, 1277 | 1278 | callsArg: function callsArg(pos) { 1279 | if (typeof pos != "number") { 1280 | throw new TypeError("argument index is not number"); 1281 | } 1282 | 1283 | this.callArgAt = pos; 1284 | this.callbackArguments = []; 1285 | 1286 | return this; 1287 | }, 1288 | 1289 | callsArgOn: function callsArgOn(pos, context) { 1290 | if (typeof pos != "number") { 1291 | throw new TypeError("argument index is not number"); 1292 | } 1293 | if (typeof context != "object") { 1294 | throw new TypeError("argument context is not an object"); 1295 | } 1296 | 1297 | this.callArgAt = pos; 1298 | this.callbackArguments = []; 1299 | this.callbackContext = context; 1300 | 1301 | return this; 1302 | }, 1303 | 1304 | callsArgWith: function callsArgWith(pos) { 1305 | if (typeof pos != "number") { 1306 | throw new TypeError("argument index is not number"); 1307 | } 1308 | 1309 | this.callArgAt = pos; 1310 | this.callbackArguments = slice.call(arguments, 1); 1311 | 1312 | return this; 1313 | }, 1314 | 1315 | callsArgOnWith: function callsArgWith(pos, context) { 1316 | if (typeof pos != "number") { 1317 | throw new TypeError("argument index is not number"); 1318 | } 1319 | if (typeof context != "object") { 1320 | throw new TypeError("argument context is not an object"); 1321 | } 1322 | 1323 | this.callArgAt = pos; 1324 | this.callbackArguments = slice.call(arguments, 2); 1325 | this.callbackContext = context; 1326 | 1327 | return this; 1328 | }, 1329 | 1330 | yields: function () { 1331 | this.callArgAt = -1; 1332 | this.callbackArguments = slice.call(arguments, 0); 1333 | 1334 | return this; 1335 | }, 1336 | 1337 | yieldsOn: function (context) { 1338 | if (typeof context != "object") { 1339 | throw new TypeError("argument context is not an object"); 1340 | } 1341 | 1342 | this.callArgAt = -1; 1343 | this.callbackArguments = slice.call(arguments, 1); 1344 | this.callbackContext = context; 1345 | 1346 | return this; 1347 | }, 1348 | 1349 | yieldsTo: function (prop) { 1350 | this.callArgAt = -1; 1351 | this.callArgProp = prop; 1352 | this.callbackArguments = slice.call(arguments, 1); 1353 | 1354 | return this; 1355 | }, 1356 | 1357 | yieldsToOn: function (prop, context) { 1358 | if (typeof context != "object") { 1359 | throw new TypeError("argument context is not an object"); 1360 | } 1361 | 1362 | this.callArgAt = -1; 1363 | this.callArgProp = prop; 1364 | this.callbackArguments = slice.call(arguments, 2); 1365 | this.callbackContext = context; 1366 | 1367 | return this; 1368 | } 1369 | }; 1370 | }())); 1371 | 1372 | if (commonJSModule) { 1373 | module.exports = stub; 1374 | } else { 1375 | sinon.stub = stub; 1376 | } 1377 | }(typeof sinon == "object" && sinon || null)); 1378 | 1379 | /** 1380 | * @depend ../sinon.js 1381 | * @depend stub.js 1382 | */ 1383 | /*jslint eqeqeq: false, onevar: false, nomen: false*/ 1384 | /*global module, require, sinon*/ 1385 | /** 1386 | * Mock functions. 1387 | * 1388 | * @author Christian Johansen (christian@cjohansen.no) 1389 | * @license BSD 1390 | * 1391 | * Copyright (c) 2010-2011 Christian Johansen 1392 | */ 1393 | 1394 | (function (sinon) { 1395 | var commonJSModule = typeof module == "object" && typeof require == "function"; 1396 | var push = [].push; 1397 | 1398 | if (!sinon && commonJSModule) { 1399 | sinon = require("../sinon"); 1400 | } 1401 | 1402 | if (!sinon) { 1403 | return; 1404 | } 1405 | 1406 | function mock(object) { 1407 | if (!object) { 1408 | return sinon.expectation.create("Anonymous mock"); 1409 | } 1410 | 1411 | return mock.create(object); 1412 | } 1413 | 1414 | sinon.mock = mock; 1415 | 1416 | sinon.extend(mock, (function () { 1417 | function each(collection, callback) { 1418 | if (!collection) { 1419 | return; 1420 | } 1421 | 1422 | for (var i = 0, l = collection.length; i < l; i += 1) { 1423 | callback(collection[i]); 1424 | } 1425 | } 1426 | 1427 | return { 1428 | create: function create(object) { 1429 | if (!object) { 1430 | throw new TypeError("object is null"); 1431 | } 1432 | 1433 | var mockObject = sinon.extend({}, mock); 1434 | mockObject.object = object; 1435 | delete mockObject.create; 1436 | 1437 | return mockObject; 1438 | }, 1439 | 1440 | expects: function expects(method) { 1441 | if (!method) { 1442 | throw new TypeError("method is falsy"); 1443 | } 1444 | 1445 | if (!this.expectations) { 1446 | this.expectations = {}; 1447 | this.proxies = []; 1448 | } 1449 | 1450 | if (!this.expectations[method]) { 1451 | this.expectations[method] = []; 1452 | var mockObject = this; 1453 | 1454 | sinon.wrapMethod(this.object, method, function () { 1455 | return mockObject.invokeMethod(method, this, arguments); 1456 | }); 1457 | 1458 | push.call(this.proxies, method); 1459 | } 1460 | 1461 | var expectation = sinon.expectation.create(method); 1462 | push.call(this.expectations[method], expectation); 1463 | 1464 | return expectation; 1465 | }, 1466 | 1467 | restore: function restore() { 1468 | var object = this.object; 1469 | 1470 | each(this.proxies, function (proxy) { 1471 | if (typeof object[proxy].restore == "function") { 1472 | object[proxy].restore(); 1473 | } 1474 | }); 1475 | }, 1476 | 1477 | verify: function verify() { 1478 | var expectations = this.expectations || {}; 1479 | var messages = [], met = []; 1480 | 1481 | each(this.proxies, function (proxy) { 1482 | each(expectations[proxy], function (expectation) { 1483 | if (!expectation.met()) { 1484 | push.call(messages, expectation.toString()); 1485 | } else { 1486 | push.call(met, expectation.toString()); 1487 | } 1488 | }); 1489 | }); 1490 | 1491 | this.restore(); 1492 | 1493 | if (messages.length > 0) { 1494 | sinon.expectation.fail(messages.concat(met).join("\n")); 1495 | } 1496 | 1497 | return true; 1498 | }, 1499 | 1500 | invokeMethod: function invokeMethod(method, thisValue, args) { 1501 | var expectations = this.expectations && this.expectations[method]; 1502 | var length = expectations && expectations.length || 0; 1503 | 1504 | for (var i = 0; i < length; i += 1) { 1505 | if (!expectations[i].met() && 1506 | expectations[i].allowsCall(thisValue, args)) { 1507 | return expectations[i].apply(thisValue, args); 1508 | } 1509 | } 1510 | 1511 | var messages = []; 1512 | 1513 | for (i = 0; i < length; i += 1) { 1514 | push.call(messages, " " + expectations[i].toString()); 1515 | } 1516 | 1517 | messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ 1518 | proxy: method, 1519 | args: args 1520 | })); 1521 | 1522 | sinon.expectation.fail(messages.join("\n")); 1523 | } 1524 | }; 1525 | }())); 1526 | 1527 | var times = sinon.timesInWords; 1528 | 1529 | sinon.expectation = (function () { 1530 | var slice = Array.prototype.slice; 1531 | var _invoke = sinon.spy.invoke; 1532 | 1533 | function callCountInWords(callCount) { 1534 | if (callCount == 0) { 1535 | return "never called"; 1536 | } else { 1537 | return "called " + times(callCount); 1538 | } 1539 | } 1540 | 1541 | function expectedCallCountInWords(expectation) { 1542 | var min = expectation.minCalls; 1543 | var max = expectation.maxCalls; 1544 | 1545 | if (typeof min == "number" && typeof max == "number") { 1546 | var str = times(min); 1547 | 1548 | if (min != max) { 1549 | str = "at least " + str + " and at most " + times(max); 1550 | } 1551 | 1552 | return str; 1553 | } 1554 | 1555 | if (typeof min == "number") { 1556 | return "at least " + times(min); 1557 | } 1558 | 1559 | return "at most " + times(max); 1560 | } 1561 | 1562 | function receivedMinCalls(expectation) { 1563 | var hasMinLimit = typeof expectation.minCalls == "number"; 1564 | return !hasMinLimit || expectation.callCount >= expectation.minCalls; 1565 | } 1566 | 1567 | function receivedMaxCalls(expectation) { 1568 | if (typeof expectation.maxCalls != "number") { 1569 | return false; 1570 | } 1571 | 1572 | return expectation.callCount == expectation.maxCalls; 1573 | } 1574 | 1575 | return { 1576 | minCalls: 1, 1577 | maxCalls: 1, 1578 | 1579 | create: function create(methodName) { 1580 | var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); 1581 | delete expectation.create; 1582 | expectation.method = methodName; 1583 | 1584 | return expectation; 1585 | }, 1586 | 1587 | invoke: function invoke(func, thisValue, args) { 1588 | this.verifyCallAllowed(thisValue, args); 1589 | 1590 | return _invoke.apply(this, arguments); 1591 | }, 1592 | 1593 | atLeast: function atLeast(num) { 1594 | if (typeof num != "number") { 1595 | throw new TypeError("'" + num + "' is not number"); 1596 | } 1597 | 1598 | if (!this.limitsSet) { 1599 | this.maxCalls = null; 1600 | this.limitsSet = true; 1601 | } 1602 | 1603 | this.minCalls = num; 1604 | 1605 | return this; 1606 | }, 1607 | 1608 | atMost: function atMost(num) { 1609 | if (typeof num != "number") { 1610 | throw new TypeError("'" + num + "' is not number"); 1611 | } 1612 | 1613 | if (!this.limitsSet) { 1614 | this.minCalls = null; 1615 | this.limitsSet = true; 1616 | } 1617 | 1618 | this.maxCalls = num; 1619 | 1620 | return this; 1621 | }, 1622 | 1623 | never: function never() { 1624 | return this.exactly(0); 1625 | }, 1626 | 1627 | once: function once() { 1628 | return this.exactly(1); 1629 | }, 1630 | 1631 | twice: function twice() { 1632 | return this.exactly(2); 1633 | }, 1634 | 1635 | thrice: function thrice() { 1636 | return this.exactly(3); 1637 | }, 1638 | 1639 | exactly: function exactly(num) { 1640 | if (typeof num != "number") { 1641 | throw new TypeError("'" + num + "' is not a number"); 1642 | } 1643 | 1644 | this.atLeast(num); 1645 | return this.atMost(num); 1646 | }, 1647 | 1648 | met: function met() { 1649 | return !this.failed && receivedMinCalls(this); 1650 | }, 1651 | 1652 | verifyCallAllowed: function verifyCallAllowed(thisValue, args) { 1653 | if (receivedMaxCalls(this)) { 1654 | this.failed = true; 1655 | sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); 1656 | } 1657 | 1658 | if ("expectedThis" in this && this.expectedThis !== thisValue) { 1659 | sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + 1660 | this.expectedThis); 1661 | } 1662 | 1663 | if (!("expectedArguments" in this)) { 1664 | return; 1665 | } 1666 | 1667 | if (!args || args.length === 0) { 1668 | sinon.expectation.fail(this.method + " received no arguments, expected " + 1669 | this.expectedArguments.join()); 1670 | } 1671 | 1672 | if (args.length < this.expectedArguments.length) { 1673 | sinon.expectation.fail(this.method + " received too few arguments (" + args.join() + 1674 | "), expected " + this.expectedArguments.join()); 1675 | } 1676 | 1677 | if (this.expectsExactArgCount && 1678 | args.length != this.expectedArguments.length) { 1679 | sinon.expectation.fail(this.method + " received too many arguments (" + args.join() + 1680 | "), expected " + this.expectedArguments.join()); 1681 | } 1682 | 1683 | for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { 1684 | if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { 1685 | sinon.expectation.fail(this.method + " received wrong arguments (" + args.join() + 1686 | "), expected " + this.expectedArguments.join()); 1687 | } 1688 | } 1689 | }, 1690 | 1691 | allowsCall: function allowsCall(thisValue, args) { 1692 | if (this.met()) { 1693 | return false; 1694 | } 1695 | 1696 | if ("expectedThis" in this && this.expectedThis !== thisValue) { 1697 | return false; 1698 | } 1699 | 1700 | if (!("expectedArguments" in this)) { 1701 | return true; 1702 | } 1703 | 1704 | args = args || []; 1705 | 1706 | if (args.length < this.expectedArguments.length) { 1707 | return false; 1708 | } 1709 | 1710 | if (this.expectsExactArgCount && 1711 | args.length != this.expectedArguments.length) { 1712 | return false; 1713 | } 1714 | 1715 | for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { 1716 | if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { 1717 | return false; 1718 | } 1719 | } 1720 | 1721 | return true; 1722 | }, 1723 | 1724 | withArgs: function withArgs() { 1725 | this.expectedArguments = slice.call(arguments); 1726 | return this; 1727 | }, 1728 | 1729 | withExactArgs: function withExactArgs() { 1730 | this.withArgs.apply(this, arguments); 1731 | this.expectsExactArgCount = true; 1732 | return this; 1733 | }, 1734 | 1735 | on: function on(thisValue) { 1736 | this.expectedThis = thisValue; 1737 | return this; 1738 | }, 1739 | 1740 | toString: function () { 1741 | var args = (this.expectedArguments || []).slice(); 1742 | 1743 | if (!this.expectsExactArgCount) { 1744 | push.call(args, "[...]"); 1745 | } 1746 | 1747 | var callStr = sinon.spyCall.toString.call({ 1748 | proxy: this.method, args: args 1749 | }); 1750 | 1751 | var message = callStr.replace(", [...", "[, ...") + " " + 1752 | expectedCallCountInWords(this); 1753 | 1754 | if (this.met()) { 1755 | return "Expectation met: " + message; 1756 | } 1757 | 1758 | return "Expected " + message + " (" + 1759 | callCountInWords(this.callCount) + ")"; 1760 | }, 1761 | 1762 | verify: function verify() { 1763 | if (!this.met()) { 1764 | sinon.expectation.fail(this.toString()); 1765 | } 1766 | 1767 | return true; 1768 | }, 1769 | 1770 | fail: function (message) { 1771 | var exception = new Error(message); 1772 | exception.name = "ExpectationError"; 1773 | 1774 | throw exception; 1775 | } 1776 | }; 1777 | }()); 1778 | 1779 | if (commonJSModule) { 1780 | module.exports = mock; 1781 | } else { 1782 | sinon.mock = mock; 1783 | } 1784 | }(typeof sinon == "object" && sinon || null)); 1785 | 1786 | /** 1787 | * @depend ../sinon.js 1788 | * @depend stub.js 1789 | * @depend mock.js 1790 | */ 1791 | /*jslint eqeqeq: false, onevar: false, forin: true*/ 1792 | /*global module, require, sinon*/ 1793 | /** 1794 | * Collections of stubs, spies and mocks. 1795 | * 1796 | * @author Christian Johansen (christian@cjohansen.no) 1797 | * @license BSD 1798 | * 1799 | * Copyright (c) 2010-2011 Christian Johansen 1800 | */ 1801 | 1802 | (function (sinon) { 1803 | var commonJSModule = typeof module == "object" && typeof require == "function"; 1804 | var push = [].push; 1805 | 1806 | if (!sinon && commonJSModule) { 1807 | sinon = require("../sinon"); 1808 | } 1809 | 1810 | if (!sinon) { 1811 | return; 1812 | } 1813 | 1814 | function getFakes(fakeCollection) { 1815 | if (!fakeCollection.fakes) { 1816 | fakeCollection.fakes = []; 1817 | } 1818 | 1819 | return fakeCollection.fakes; 1820 | } 1821 | 1822 | function each(fakeCollection, method) { 1823 | var fakes = getFakes(fakeCollection); 1824 | 1825 | for (var i = 0, l = fakes.length; i < l; i += 1) { 1826 | if (typeof fakes[i][method] == "function") { 1827 | fakes[i][method](); 1828 | } 1829 | } 1830 | } 1831 | 1832 | function compact(fakeCollection) { 1833 | var fakes = getFakes(fakeCollection); 1834 | var i = 0; 1835 | while (i < fakes.length) { 1836 | fakes.splice(i, 1); 1837 | } 1838 | } 1839 | 1840 | var collection = { 1841 | verify: function resolve() { 1842 | each(this, "verify"); 1843 | }, 1844 | 1845 | restore: function restore() { 1846 | each(this, "restore"); 1847 | compact(this); 1848 | }, 1849 | 1850 | verifyAndRestore: function verifyAndRestore() { 1851 | var exception; 1852 | 1853 | try { 1854 | this.verify(); 1855 | } catch (e) { 1856 | exception = e; 1857 | } 1858 | 1859 | this.restore(); 1860 | 1861 | if (exception) { 1862 | throw exception; 1863 | } 1864 | }, 1865 | 1866 | add: function add(fake) { 1867 | push.call(getFakes(this), fake); 1868 | return fake; 1869 | }, 1870 | 1871 | spy: function spy() { 1872 | return this.add(sinon.spy.apply(sinon, arguments)); 1873 | }, 1874 | 1875 | stub: function stub(object, property, value) { 1876 | if (property) { 1877 | var original = object[property]; 1878 | 1879 | if (typeof original != "function") { 1880 | if (!object.hasOwnProperty(property)) { 1881 | throw new TypeError("Cannot stub non-existent own property " + property); 1882 | } 1883 | 1884 | object[property] = value; 1885 | 1886 | return this.add({ 1887 | restore: function () { 1888 | object[property] = original; 1889 | } 1890 | }); 1891 | } 1892 | } 1893 | 1894 | return this.add(sinon.stub.apply(sinon, arguments)); 1895 | }, 1896 | 1897 | mock: function mock() { 1898 | return this.add(sinon.mock.apply(sinon, arguments)); 1899 | }, 1900 | 1901 | inject: function inject(obj) { 1902 | var col = this; 1903 | 1904 | obj.spy = function () { 1905 | return col.spy.apply(col, arguments); 1906 | }; 1907 | 1908 | obj.stub = function () { 1909 | return col.stub.apply(col, arguments); 1910 | }; 1911 | 1912 | obj.mock = function () { 1913 | return col.mock.apply(col, arguments); 1914 | }; 1915 | 1916 | return obj; 1917 | } 1918 | }; 1919 | 1920 | if (commonJSModule) { 1921 | module.exports = collection; 1922 | } else { 1923 | sinon.collection = collection; 1924 | } 1925 | }(typeof sinon == "object" && sinon || null)); 1926 | 1927 | /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ 1928 | /*global module, require, window*/ 1929 | /** 1930 | * Fake timer API 1931 | * setTimeout 1932 | * setInterval 1933 | * clearTimeout 1934 | * clearInterval 1935 | * tick 1936 | * reset 1937 | * Date 1938 | * 1939 | * Inspired by jsUnitMockTimeOut from JsUnit 1940 | * 1941 | * @author Christian Johansen (christian@cjohansen.no) 1942 | * @license BSD 1943 | * 1944 | * Copyright (c) 2010-2011 Christian Johansen 1945 | */ 1946 | 1947 | if (typeof sinon == "undefined") { 1948 | var sinon = {}; 1949 | } 1950 | 1951 | (function (global) { 1952 | var id = 1; 1953 | 1954 | function addTimer(args, recurring) { 1955 | if (args.length === 0) { 1956 | throw new Error("Function requires at least 1 parameter"); 1957 | } 1958 | 1959 | var toId = id++; 1960 | var delay = args[1] || 0; 1961 | 1962 | if (!this.timeouts) { 1963 | this.timeouts = {}; 1964 | } 1965 | 1966 | this.timeouts[toId] = { 1967 | id: toId, 1968 | func: args[0], 1969 | callAt: this.now + delay 1970 | }; 1971 | 1972 | if (recurring === true) { 1973 | this.timeouts[toId].interval = delay; 1974 | } 1975 | 1976 | return toId; 1977 | } 1978 | 1979 | function parseTime(str) { 1980 | if (!str) { 1981 | return 0; 1982 | } 1983 | 1984 | var strings = str.split(":"); 1985 | var l = strings.length, i = l; 1986 | var ms = 0, parsed; 1987 | 1988 | if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { 1989 | throw new Error("tick only understands numbers and 'h:m:s'"); 1990 | } 1991 | 1992 | while (i--) { 1993 | parsed = parseInt(strings[i], 10); 1994 | 1995 | if (parsed >= 60) { 1996 | throw new Error("Invalid time " + str); 1997 | } 1998 | 1999 | ms += parsed * Math.pow(60, (l - i - 1)); 2000 | } 2001 | 2002 | return ms * 1000; 2003 | } 2004 | 2005 | function createObject(object) { 2006 | var newObject; 2007 | 2008 | if (Object.create) { 2009 | newObject = Object.create(object); 2010 | } else { 2011 | var F = function () {}; 2012 | F.prototype = object; 2013 | newObject = new F(); 2014 | } 2015 | 2016 | newObject.Date.clock = newObject; 2017 | return newObject; 2018 | } 2019 | 2020 | sinon.clock = { 2021 | now: 0, 2022 | 2023 | create: function create(now) { 2024 | var clock = createObject(this); 2025 | 2026 | if (typeof now == "number") { 2027 | clock.now = now; 2028 | } 2029 | 2030 | if (!!now && typeof now == "object") { 2031 | throw new TypeError("now should be milliseconds since UNIX epoch"); 2032 | } 2033 | 2034 | return clock; 2035 | }, 2036 | 2037 | setTimeout: function setTimeout(callback, timeout) { 2038 | return addTimer.call(this, arguments, false); 2039 | }, 2040 | 2041 | clearTimeout: function clearTimeout(timerId) { 2042 | if (!this.timeouts) { 2043 | this.timeouts = []; 2044 | } 2045 | 2046 | if (timerId in this.timeouts) { 2047 | delete this.timeouts[timerId]; 2048 | } 2049 | }, 2050 | 2051 | setInterval: function setInterval(callback, timeout) { 2052 | return addTimer.call(this, arguments, true); 2053 | }, 2054 | 2055 | clearInterval: function clearInterval(timerId) { 2056 | this.clearTimeout(timerId); 2057 | }, 2058 | 2059 | tick: function tick(ms) { 2060 | ms = typeof ms == "number" ? ms : parseTime(ms); 2061 | var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; 2062 | var timer = this.firstTimerInRange(tickFrom, tickTo); 2063 | 2064 | var firstException; 2065 | while (timer && tickFrom <= tickTo) { 2066 | if (this.timeouts[timer.id]) { 2067 | tickFrom = this.now = timer.callAt; 2068 | try { 2069 | this.callTimer(timer); 2070 | } catch (e) { 2071 | firstException = firstException || e; 2072 | } 2073 | } 2074 | 2075 | timer = this.firstTimerInRange(previous, tickTo); 2076 | previous = tickFrom; 2077 | } 2078 | 2079 | this.now = tickTo; 2080 | 2081 | if (firstException) { 2082 | throw firstException; 2083 | } 2084 | }, 2085 | 2086 | firstTimerInRange: function (from, to) { 2087 | var timer, smallest, originalTimer; 2088 | 2089 | for (var id in this.timeouts) { 2090 | if (this.timeouts.hasOwnProperty(id)) { 2091 | if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { 2092 | continue; 2093 | } 2094 | 2095 | if (!smallest || this.timeouts[id].callAt < smallest) { 2096 | originalTimer = this.timeouts[id]; 2097 | smallest = this.timeouts[id].callAt; 2098 | 2099 | timer = { 2100 | func: this.timeouts[id].func, 2101 | callAt: this.timeouts[id].callAt, 2102 | interval: this.timeouts[id].interval, 2103 | id: this.timeouts[id].id 2104 | }; 2105 | } 2106 | } 2107 | } 2108 | 2109 | return timer || null; 2110 | }, 2111 | 2112 | callTimer: function (timer) { 2113 | try { 2114 | if (typeof timer.func == "function") { 2115 | timer.func.call(null); 2116 | } else { 2117 | eval(timer.func); 2118 | } 2119 | } catch (e) { 2120 | var exception = e; 2121 | } 2122 | 2123 | if (!this.timeouts[timer.id]) { 2124 | if (exception) { 2125 | throw exception; 2126 | } 2127 | return; 2128 | } 2129 | 2130 | if (typeof timer.interval == "number") { 2131 | this.timeouts[timer.id].callAt += timer.interval; 2132 | } else { 2133 | delete this.timeouts[timer.id]; 2134 | } 2135 | 2136 | if (exception) { 2137 | throw exception; 2138 | } 2139 | }, 2140 | 2141 | reset: function reset() { 2142 | this.timeouts = {}; 2143 | }, 2144 | 2145 | Date: (function () { 2146 | var NativeDate = Date; 2147 | 2148 | function ClockDate(year, month, date, hour, minute, second, ms) { 2149 | // Defensive and verbose to avoid potential harm in passing 2150 | // explicit undefined when user does not pass argument 2151 | switch (arguments.length) { 2152 | case 0: 2153 | return new NativeDate(ClockDate.clock.now); 2154 | case 1: 2155 | return new NativeDate(year); 2156 | case 2: 2157 | return new NativeDate(year, month); 2158 | case 3: 2159 | return new NativeDate(year, month, date); 2160 | case 4: 2161 | return new NativeDate(year, month, date, hour); 2162 | case 5: 2163 | return new NativeDate(year, month, date, hour, minute); 2164 | case 6: 2165 | return new NativeDate(year, month, date, hour, minute, second); 2166 | default: 2167 | return new NativeDate(year, month, date, hour, minute, second, ms); 2168 | } 2169 | } 2170 | 2171 | return mirrorDateProperties(ClockDate, NativeDate); 2172 | }()) 2173 | }; 2174 | 2175 | function mirrorDateProperties(target, source) { 2176 | if (source.now) { 2177 | target.now = function now() { 2178 | return target.clock.now; 2179 | }; 2180 | } else { 2181 | delete target.now; 2182 | } 2183 | 2184 | if (source.toSource) { 2185 | target.toSource = function toSource() { 2186 | return source.toSource(); 2187 | }; 2188 | } else { 2189 | delete target.toSource; 2190 | } 2191 | 2192 | target.toString = function toString() { 2193 | return source.toString(); 2194 | }; 2195 | 2196 | target.prototype = source.prototype; 2197 | target.parse = source.parse; 2198 | target.UTC = source.UTC; 2199 | target.prototype.toUTCString = source.prototype.toUTCString; 2200 | return target; 2201 | } 2202 | 2203 | var methods = ["Date", "setTimeout", "setInterval", 2204 | "clearTimeout", "clearInterval"]; 2205 | 2206 | function restore() { 2207 | var method; 2208 | 2209 | for (var i = 0, l = this.methods.length; i < l; i++) { 2210 | method = this.methods[i]; 2211 | global[method] = this["_" + method]; 2212 | } 2213 | } 2214 | 2215 | function stubGlobal(method, clock) { 2216 | clock["_" + method] = global[method]; 2217 | 2218 | if (method == "Date") { 2219 | var date = mirrorDateProperties(clock[method], global[method]); 2220 | global[method] = date; 2221 | } else { 2222 | global[method] = function () { 2223 | return clock[method].apply(clock, arguments); 2224 | }; 2225 | 2226 | for (var prop in clock[method]) { 2227 | if (clock[method].hasOwnProperty(prop)) { 2228 | global[method][prop] = clock[method][prop]; 2229 | } 2230 | } 2231 | } 2232 | 2233 | global[method].clock = clock; 2234 | } 2235 | 2236 | sinon.useFakeTimers = function useFakeTimers(now) { 2237 | var clock = sinon.clock.create(now); 2238 | clock.restore = restore; 2239 | clock.methods = Array.prototype.slice.call(arguments, 2240 | typeof now == "number" ? 1 : 0); 2241 | 2242 | if (clock.methods.length === 0) { 2243 | clock.methods = methods; 2244 | } 2245 | 2246 | for (var i = 0, l = clock.methods.length; i < l; i++) { 2247 | stubGlobal(clock.methods[i], clock); 2248 | } 2249 | 2250 | return clock; 2251 | }; 2252 | }(typeof global != "undefined" && typeof global !== "function" ? global : this)); 2253 | 2254 | sinon.timers = { 2255 | setTimeout: setTimeout, 2256 | clearTimeout: clearTimeout, 2257 | setInterval: setInterval, 2258 | clearInterval: clearInterval, 2259 | Date: Date 2260 | }; 2261 | 2262 | if (typeof module == "object" && typeof require == "function") { 2263 | module.exports = sinon; 2264 | } 2265 | 2266 | /*jslint eqeqeq: false, onevar: false*/ 2267 | /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ 2268 | /** 2269 | * Minimal Event interface implementation 2270 | * 2271 | * Original implementation by Sven Fuchs: https://gist.github.com/995028 2272 | * Modifications and tests by Christian Johansen. 2273 | * 2274 | * @author Sven Fuchs (svenfuchs@artweb-design.de) 2275 | * @author Christian Johansen (christian@cjohansen.no) 2276 | * @license BSD 2277 | * 2278 | * Copyright (c) 2011 Sven Fuchs, Christian Johansen 2279 | */ 2280 | 2281 | if (typeof sinon == "undefined") { 2282 | this.sinon = {}; 2283 | } 2284 | 2285 | (function () { 2286 | var push = [].push; 2287 | 2288 | sinon.Event = function Event(type, bubbles, cancelable) { 2289 | this.initEvent(type, bubbles, cancelable); 2290 | }; 2291 | 2292 | sinon.Event.prototype = { 2293 | initEvent: function(type, bubbles, cancelable) { 2294 | this.type = type; 2295 | this.bubbles = bubbles; 2296 | this.cancelable = cancelable; 2297 | }, 2298 | 2299 | stopPropagation: function () {}, 2300 | 2301 | preventDefault: function () { 2302 | this.defaultPrevented = true; 2303 | } 2304 | }; 2305 | 2306 | sinon.EventTarget = { 2307 | addEventListener: function addEventListener(event, listener, useCapture) { 2308 | this.eventListeners = this.eventListeners || {}; 2309 | this.eventListeners[event] = this.eventListeners[event] || []; 2310 | push.call(this.eventListeners[event], listener); 2311 | }, 2312 | 2313 | removeEventListener: function removeEventListener(event, listener, useCapture) { 2314 | var listeners = this.eventListeners && this.eventListeners[event] || []; 2315 | 2316 | for (var i = 0, l = listeners.length; i < l; ++i) { 2317 | if (listeners[i] == listener) { 2318 | return listeners.splice(i, 1); 2319 | } 2320 | } 2321 | }, 2322 | 2323 | dispatchEvent: function dispatchEvent(event) { 2324 | var type = event.type; 2325 | var listeners = this.eventListeners && this.eventListeners[type] || []; 2326 | 2327 | for (var i = 0; i < listeners.length; i++) { 2328 | if (typeof listeners[i] == "function") { 2329 | listeners[i].call(this, event); 2330 | } else { 2331 | listeners[i].handleEvent(event); 2332 | } 2333 | } 2334 | 2335 | return !!event.defaultPrevented; 2336 | } 2337 | }; 2338 | }()); 2339 | 2340 | /** 2341 | * @depend event.js 2342 | */ 2343 | /*jslint eqeqeq: false, onevar: false*/ 2344 | /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ 2345 | /** 2346 | * Fake XMLHttpRequest object 2347 | * 2348 | * @author Christian Johansen (christian@cjohansen.no) 2349 | * @license BSD 2350 | * 2351 | * Copyright (c) 2010-2011 Christian Johansen 2352 | */ 2353 | 2354 | if (typeof sinon == "undefined") { 2355 | this.sinon = {}; 2356 | } 2357 | sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest }; 2358 | 2359 | // wrapper for global 2360 | (function(global) { 2361 | var xhr = sinon.xhr; 2362 | xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; 2363 | xhr.GlobalActiveXObject = global.ActiveXObject; 2364 | xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; 2365 | xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; 2366 | xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX 2367 | ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; 2368 | 2369 | /*jsl:ignore*/ 2370 | var unsafeHeaders = { 2371 | "Accept-Charset": true, 2372 | "Accept-Encoding": true, 2373 | "Connection": true, 2374 | "Content-Length": true, 2375 | "Cookie": true, 2376 | "Cookie2": true, 2377 | "Content-Transfer-Encoding": true, 2378 | "Date": true, 2379 | "Expect": true, 2380 | "Host": true, 2381 | "Keep-Alive": true, 2382 | "Referer": true, 2383 | "TE": true, 2384 | "Trailer": true, 2385 | "Transfer-Encoding": true, 2386 | "Upgrade": true, 2387 | "User-Agent": true, 2388 | "Via": true 2389 | }; 2390 | /*jsl:end*/ 2391 | 2392 | function FakeXMLHttpRequest() { 2393 | this.readyState = FakeXMLHttpRequest.UNSENT; 2394 | this.requestHeaders = {}; 2395 | this.requestBody = null; 2396 | this.status = 0; 2397 | this.statusText = ""; 2398 | 2399 | if (typeof FakeXMLHttpRequest.onCreate == "function") { 2400 | FakeXMLHttpRequest.onCreate(this); 2401 | } 2402 | } 2403 | 2404 | function verifyState(xhr) { 2405 | if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { 2406 | throw new Error("INVALID_STATE_ERR"); 2407 | } 2408 | 2409 | if (xhr.sendFlag) { 2410 | throw new Error("INVALID_STATE_ERR"); 2411 | } 2412 | } 2413 | 2414 | // filtering to enable a white-list version of Sinon FakeXhr, 2415 | // where whitelisted requests are passed through to real XHR 2416 | function each(collection, callback) { 2417 | if (!collection) return; 2418 | for (var i = 0, l = collection.length; i < l; i += 1) { 2419 | callback(collection[i]); 2420 | } 2421 | } 2422 | function some(collection, callback) { 2423 | for (var index = 0; index < collection.length; index++) { 2424 | if(callback(collection[index]) === true) return true; 2425 | }; 2426 | return false; 2427 | } 2428 | // largest arity in XHR is 5 - XHR#open 2429 | var apply = function(obj,method,args) { 2430 | switch(args.length) { 2431 | case 0: return obj[method](); 2432 | case 1: return obj[method](args[0]); 2433 | case 2: return obj[method](args[0],args[1]); 2434 | case 3: return obj[method](args[0],args[1],args[2]); 2435 | case 4: return obj[method](args[0],args[1],args[2],args[3]); 2436 | case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); 2437 | }; 2438 | }; 2439 | 2440 | FakeXMLHttpRequest.filters = []; 2441 | FakeXMLHttpRequest.addFilter = function(fn) { 2442 | this.filters.push(fn) 2443 | }; 2444 | var IE6Re = /MSIE 6/; 2445 | FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { 2446 | var xhr = new sinon.xhr.workingXHR(); 2447 | each(["open","setRequestHeader","send","abort","getResponseHeader", 2448 | "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], 2449 | function(method) { 2450 | fakeXhr[method] = function() { 2451 | return apply(xhr,method,arguments); 2452 | }; 2453 | }); 2454 | 2455 | var copyAttrs = function(args) { 2456 | each(args, function(attr) { 2457 | try { 2458 | fakeXhr[attr] = xhr[attr] 2459 | } catch(e) { 2460 | if(!IE6Re.test(navigator.userAgent)) throw e; 2461 | } 2462 | }); 2463 | }; 2464 | 2465 | var stateChange = function() { 2466 | fakeXhr.readyState = xhr.readyState; 2467 | if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { 2468 | copyAttrs(["status","statusText"]); 2469 | } 2470 | if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { 2471 | copyAttrs(["responseText"]); 2472 | } 2473 | if(xhr.readyState === FakeXMLHttpRequest.DONE) { 2474 | copyAttrs(["responseXML"]); 2475 | } 2476 | if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr); 2477 | }; 2478 | if(xhr.addEventListener) { 2479 | for(var event in fakeXhr.eventListeners) { 2480 | if(fakeXhr.eventListeners.hasOwnProperty(event)) { 2481 | each(fakeXhr.eventListeners[event],function(handler) { 2482 | xhr.addEventListener(event, handler); 2483 | }); 2484 | } 2485 | } 2486 | xhr.addEventListener("readystatechange",stateChange); 2487 | } else { 2488 | xhr.onreadystatechange = stateChange; 2489 | } 2490 | apply(xhr,"open",xhrArgs); 2491 | }; 2492 | FakeXMLHttpRequest.useFilters = false; 2493 | 2494 | function verifyRequestSent(xhr) { 2495 | if (xhr.readyState == FakeXMLHttpRequest.DONE) { 2496 | throw new Error("Request done"); 2497 | } 2498 | } 2499 | 2500 | function verifyHeadersReceived(xhr) { 2501 | if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { 2502 | throw new Error("No headers received"); 2503 | } 2504 | } 2505 | 2506 | function verifyResponseBodyType(body) { 2507 | if (typeof body != "string") { 2508 | var error = new Error("Attempted to respond to fake XMLHttpRequest with " + 2509 | body + ", which is not a string."); 2510 | error.name = "InvalidBodyException"; 2511 | throw error; 2512 | } 2513 | } 2514 | 2515 | sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { 2516 | async: true, 2517 | 2518 | open: function open(method, url, async, username, password) { 2519 | this.method = method; 2520 | this.url = url; 2521 | this.async = typeof async == "boolean" ? async : true; 2522 | this.username = username; 2523 | this.password = password; 2524 | this.responseText = null; 2525 | this.responseXML = null; 2526 | this.requestHeaders = {}; 2527 | this.sendFlag = false; 2528 | if(sinon.FakeXMLHttpRequest.useFilters === true) { 2529 | var xhrArgs = arguments; 2530 | var defake = some(FakeXMLHttpRequest.filters,function(filter) { 2531 | return filter.apply(this,xhrArgs) 2532 | }); 2533 | if (defake) { 2534 | return sinon.FakeXMLHttpRequest.defake(this,arguments); 2535 | } 2536 | } 2537 | this.readyStateChange(FakeXMLHttpRequest.OPENED); 2538 | }, 2539 | 2540 | readyStateChange: function readyStateChange(state) { 2541 | this.readyState = state; 2542 | 2543 | if (typeof this.onreadystatechange == "function") { 2544 | try { 2545 | this.onreadystatechange(); 2546 | } catch (e) { 2547 | sinon.logError("Fake XHR onreadystatechange handler", e); 2548 | } 2549 | } 2550 | 2551 | this.dispatchEvent(new sinon.Event("readystatechange")); 2552 | }, 2553 | 2554 | setRequestHeader: function setRequestHeader(header, value) { 2555 | verifyState(this); 2556 | 2557 | if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { 2558 | throw new Error("Refused to set unsafe header \"" + header + "\""); 2559 | } 2560 | 2561 | if (this.requestHeaders[header]) { 2562 | this.requestHeaders[header] += "," + value; 2563 | } else { 2564 | this.requestHeaders[header] = value; 2565 | } 2566 | }, 2567 | 2568 | // Helps testing 2569 | setResponseHeaders: function setResponseHeaders(headers) { 2570 | this.responseHeaders = {}; 2571 | 2572 | for (var header in headers) { 2573 | if (headers.hasOwnProperty(header)) { 2574 | this.responseHeaders[header] = headers[header]; 2575 | } 2576 | } 2577 | 2578 | if (this.async) { 2579 | this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); 2580 | } 2581 | }, 2582 | 2583 | // Currently treats ALL data as a DOMString (i.e. no Document) 2584 | send: function send(data) { 2585 | verifyState(this); 2586 | 2587 | if (!/^(get|head)$/i.test(this.method)) { 2588 | if (this.requestHeaders["Content-Type"]) { 2589 | var value = this.requestHeaders["Content-Type"].split(";"); 2590 | this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; 2591 | } else { 2592 | this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; 2593 | } 2594 | 2595 | this.requestBody = data; 2596 | } 2597 | 2598 | this.errorFlag = false; 2599 | this.sendFlag = this.async; 2600 | this.readyStateChange(FakeXMLHttpRequest.OPENED); 2601 | 2602 | if (typeof this.onSend == "function") { 2603 | this.onSend(this); 2604 | } 2605 | }, 2606 | 2607 | abort: function abort() { 2608 | this.aborted = true; 2609 | this.responseText = null; 2610 | this.errorFlag = true; 2611 | this.requestHeaders = {}; 2612 | 2613 | if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { 2614 | this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); 2615 | this.sendFlag = false; 2616 | } 2617 | 2618 | this.readyState = sinon.FakeXMLHttpRequest.UNSENT; 2619 | }, 2620 | 2621 | getResponseHeader: function getResponseHeader(header) { 2622 | if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { 2623 | return null; 2624 | } 2625 | 2626 | if (/^Set-Cookie2?$/i.test(header)) { 2627 | return null; 2628 | } 2629 | 2630 | header = header.toLowerCase(); 2631 | 2632 | for (var h in this.responseHeaders) { 2633 | if (h.toLowerCase() == header) { 2634 | return this.responseHeaders[h]; 2635 | } 2636 | } 2637 | 2638 | return null; 2639 | }, 2640 | 2641 | getAllResponseHeaders: function getAllResponseHeaders() { 2642 | if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { 2643 | return ""; 2644 | } 2645 | 2646 | var headers = ""; 2647 | 2648 | for (var header in this.responseHeaders) { 2649 | if (this.responseHeaders.hasOwnProperty(header) && 2650 | !/^Set-Cookie2?$/i.test(header)) { 2651 | headers += header + ": " + this.responseHeaders[header] + "\r\n"; 2652 | } 2653 | } 2654 | 2655 | return headers; 2656 | }, 2657 | 2658 | setResponseBody: function setResponseBody(body) { 2659 | verifyRequestSent(this); 2660 | verifyHeadersReceived(this); 2661 | verifyResponseBodyType(body); 2662 | 2663 | var chunkSize = this.chunkSize || 10; 2664 | var index = 0; 2665 | this.responseText = ""; 2666 | 2667 | do { 2668 | if (this.async) { 2669 | this.readyStateChange(FakeXMLHttpRequest.LOADING); 2670 | } 2671 | 2672 | this.responseText += body.substring(index, index + chunkSize); 2673 | index += chunkSize; 2674 | } while (index < body.length); 2675 | 2676 | var type = this.getResponseHeader("Content-Type"); 2677 | 2678 | if (this.responseText && 2679 | (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { 2680 | try { 2681 | this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); 2682 | } catch (e) { 2683 | // Unable to parse XML - no biggie 2684 | } 2685 | } 2686 | 2687 | if (this.async) { 2688 | this.readyStateChange(FakeXMLHttpRequest.DONE); 2689 | } else { 2690 | this.readyState = FakeXMLHttpRequest.DONE; 2691 | } 2692 | }, 2693 | 2694 | respond: function respond(status, headers, body) { 2695 | this.setResponseHeaders(headers || {}); 2696 | this.status = typeof status == "number" ? status : 200; 2697 | this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; 2698 | this.setResponseBody(body || ""); 2699 | } 2700 | }); 2701 | 2702 | sinon.extend(FakeXMLHttpRequest, { 2703 | UNSENT: 0, 2704 | OPENED: 1, 2705 | HEADERS_RECEIVED: 2, 2706 | LOADING: 3, 2707 | DONE: 4 2708 | }); 2709 | 2710 | // Borrowed from JSpec 2711 | FakeXMLHttpRequest.parseXML = function parseXML(text) { 2712 | var xmlDoc; 2713 | 2714 | if (typeof DOMParser != "undefined") { 2715 | var parser = new DOMParser(); 2716 | xmlDoc = parser.parseFromString(text, "text/xml"); 2717 | } else { 2718 | xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 2719 | xmlDoc.async = "false"; 2720 | xmlDoc.loadXML(text); 2721 | } 2722 | 2723 | return xmlDoc; 2724 | }; 2725 | 2726 | FakeXMLHttpRequest.statusCodes = { 2727 | 100: "Continue", 2728 | 101: "Switching Protocols", 2729 | 200: "OK", 2730 | 201: "Created", 2731 | 202: "Accepted", 2732 | 203: "Non-Authoritative Information", 2733 | 204: "No Content", 2734 | 205: "Reset Content", 2735 | 206: "Partial Content", 2736 | 300: "Multiple Choice", 2737 | 301: "Moved Permanently", 2738 | 302: "Found", 2739 | 303: "See Other", 2740 | 304: "Not Modified", 2741 | 305: "Use Proxy", 2742 | 307: "Temporary Redirect", 2743 | 400: "Bad Request", 2744 | 401: "Unauthorized", 2745 | 402: "Payment Required", 2746 | 403: "Forbidden", 2747 | 404: "Not Found", 2748 | 405: "Method Not Allowed", 2749 | 406: "Not Acceptable", 2750 | 407: "Proxy Authentication Required", 2751 | 408: "Request Timeout", 2752 | 409: "Conflict", 2753 | 410: "Gone", 2754 | 411: "Length Required", 2755 | 412: "Precondition Failed", 2756 | 413: "Request Entity Too Large", 2757 | 414: "Request-URI Too Long", 2758 | 415: "Unsupported Media Type", 2759 | 416: "Requested Range Not Satisfiable", 2760 | 417: "Expectation Failed", 2761 | 422: "Unprocessable Entity", 2762 | 500: "Internal Server Error", 2763 | 501: "Not Implemented", 2764 | 502: "Bad Gateway", 2765 | 503: "Service Unavailable", 2766 | 504: "Gateway Timeout", 2767 | 505: "HTTP Version Not Supported" 2768 | }; 2769 | 2770 | sinon.useFakeXMLHttpRequest = function () { 2771 | sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { 2772 | if (xhr.supportsXHR) { 2773 | global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; 2774 | } 2775 | 2776 | if (xhr.supportsActiveX) { 2777 | global.ActiveXObject = xhr.GlobalActiveXObject; 2778 | } 2779 | 2780 | delete sinon.FakeXMLHttpRequest.restore; 2781 | 2782 | if (keepOnCreate !== true) { 2783 | delete sinon.FakeXMLHttpRequest.onCreate; 2784 | } 2785 | }; 2786 | if (xhr.supportsXHR) { 2787 | global.XMLHttpRequest = sinon.FakeXMLHttpRequest; 2788 | } 2789 | 2790 | if (xhr.supportsActiveX) { 2791 | global.ActiveXObject = function ActiveXObject(objId) { 2792 | if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { 2793 | 2794 | return new sinon.FakeXMLHttpRequest(); 2795 | } 2796 | 2797 | return new xhr.GlobalActiveXObject(objId); 2798 | }; 2799 | } 2800 | 2801 | return sinon.FakeXMLHttpRequest; 2802 | }; 2803 | 2804 | sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; 2805 | })(this); 2806 | 2807 | if (typeof module == "object" && typeof require == "function") { 2808 | module.exports = sinon; 2809 | } 2810 | 2811 | /** 2812 | * @depend fake_xml_http_request.js 2813 | */ 2814 | /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ 2815 | /*global module, require, window*/ 2816 | /** 2817 | * The Sinon "server" mimics a web server that receives requests from 2818 | * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, 2819 | * both synchronously and asynchronously. To respond synchronuously, canned 2820 | * answers have to be provided upfront. 2821 | * 2822 | * @author Christian Johansen (christian@cjohansen.no) 2823 | * @license BSD 2824 | * 2825 | * Copyright (c) 2010-2011 Christian Johansen 2826 | */ 2827 | 2828 | if (typeof sinon == "undefined") { 2829 | var sinon = {}; 2830 | } 2831 | 2832 | sinon.fakeServer = (function () { 2833 | var push = [].push; 2834 | function F() {} 2835 | 2836 | function create(proto) { 2837 | F.prototype = proto; 2838 | return new F(); 2839 | } 2840 | 2841 | function responseArray(handler) { 2842 | var response = handler; 2843 | 2844 | if (Object.prototype.toString.call(handler) != "[object Array]") { 2845 | response = [200, {}, handler]; 2846 | } 2847 | 2848 | if (typeof response[2] != "string") { 2849 | throw new TypeError("Fake server response body should be string, but was " + 2850 | typeof response[2]); 2851 | } 2852 | 2853 | return response; 2854 | } 2855 | 2856 | var wloc = window.location; 2857 | var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); 2858 | 2859 | function matchOne(response, reqMethod, reqUrl) { 2860 | var rmeth = response.method; 2861 | var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); 2862 | var url = response.url; 2863 | var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); 2864 | 2865 | return matchMethod && matchUrl; 2866 | } 2867 | 2868 | function match(response, request) { 2869 | var requestMethod = this.getHTTPMethod(request); 2870 | var requestUrl = request.url; 2871 | 2872 | if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { 2873 | requestUrl = requestUrl.replace(rCurrLoc, ""); 2874 | } 2875 | 2876 | if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { 2877 | if (typeof response.response == "function") { 2878 | var ru = response.url; 2879 | var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1)); 2880 | return response.response.apply(response, args); 2881 | } 2882 | 2883 | return true; 2884 | } 2885 | 2886 | return false; 2887 | } 2888 | 2889 | return { 2890 | create: function () { 2891 | var server = create(this); 2892 | this.xhr = sinon.useFakeXMLHttpRequest(); 2893 | server.requests = []; 2894 | 2895 | this.xhr.onCreate = function (xhrObj) { 2896 | server.addRequest(xhrObj); 2897 | }; 2898 | 2899 | return server; 2900 | }, 2901 | 2902 | addRequest: function addRequest(xhrObj) { 2903 | var server = this; 2904 | push.call(this.requests, xhrObj); 2905 | 2906 | xhrObj.onSend = function () { 2907 | server.handleRequest(this); 2908 | }; 2909 | 2910 | if (this.autoRespond && !this.responding) { 2911 | setTimeout(function () { 2912 | server.responding = false; 2913 | server.respond(); 2914 | }, this.autoRespondAfter || 10); 2915 | 2916 | this.responding = true; 2917 | } 2918 | }, 2919 | 2920 | getHTTPMethod: function getHTTPMethod(request) { 2921 | if (this.fakeHTTPMethods && /post/i.test(request.method)) { 2922 | var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); 2923 | return !!matches ? matches[1] : request.method; 2924 | } 2925 | 2926 | return request.method; 2927 | }, 2928 | 2929 | handleRequest: function handleRequest(xhr) { 2930 | if (xhr.async) { 2931 | if (!this.queue) { 2932 | this.queue = []; 2933 | } 2934 | 2935 | push.call(this.queue, xhr); 2936 | } else { 2937 | this.processRequest(xhr); 2938 | } 2939 | }, 2940 | 2941 | respondWith: function respondWith(method, url, body) { 2942 | if (arguments.length == 1 && typeof method != "function") { 2943 | this.response = responseArray(method); 2944 | return; 2945 | } 2946 | 2947 | if (!this.responses) { this.responses = []; } 2948 | 2949 | if (arguments.length == 1) { 2950 | body = method; 2951 | url = method = null; 2952 | } 2953 | 2954 | if (arguments.length == 2) { 2955 | body = url; 2956 | url = method; 2957 | method = null; 2958 | } 2959 | 2960 | push.call(this.responses, { 2961 | method: method, 2962 | url: url, 2963 | response: typeof body == "function" ? body : responseArray(body) 2964 | }); 2965 | }, 2966 | 2967 | respond: function respond() { 2968 | if (arguments.length > 0) this.respondWith.apply(this, arguments); 2969 | var queue = this.queue || []; 2970 | var request; 2971 | 2972 | while(request = queue.shift()) { 2973 | this.processRequest(request); 2974 | } 2975 | }, 2976 | 2977 | processRequest: function processRequest(request) { 2978 | try { 2979 | if (request.aborted) { 2980 | return; 2981 | } 2982 | 2983 | var response = this.response || [404, {}, ""]; 2984 | 2985 | if (this.responses) { 2986 | for (var i = 0, l = this.responses.length; i < l; i++) { 2987 | if (match.call(this, this.responses[i], request)) { 2988 | response = this.responses[i].response; 2989 | break; 2990 | } 2991 | } 2992 | } 2993 | 2994 | if (request.readyState != 4) { 2995 | request.respond(response[0], response[1], response[2]); 2996 | } 2997 | } catch (e) { 2998 | sinon.logError("Fake server request processing", e); 2999 | } 3000 | }, 3001 | 3002 | restore: function restore() { 3003 | return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); 3004 | } 3005 | }; 3006 | }()); 3007 | 3008 | if (typeof module == "object" && typeof require == "function") { 3009 | module.exports = sinon; 3010 | } 3011 | 3012 | /** 3013 | * @depend fake_server.js 3014 | * @depend fake_timers.js 3015 | */ 3016 | /*jslint browser: true, eqeqeq: false, onevar: false*/ 3017 | /*global sinon*/ 3018 | /** 3019 | * Add-on for sinon.fakeServer that automatically handles a fake timer along with 3020 | * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery 3021 | * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, 3022 | * it polls the object for completion with setInterval. Dispite the direct 3023 | * motivation, there is nothing jQuery-specific in this file, so it can be used 3024 | * in any environment where the ajax implementation depends on setInterval or 3025 | * setTimeout. 3026 | * 3027 | * @author Christian Johansen (christian@cjohansen.no) 3028 | * @license BSD 3029 | * 3030 | * Copyright (c) 2010-2011 Christian Johansen 3031 | */ 3032 | 3033 | (function () { 3034 | function Server() {} 3035 | Server.prototype = sinon.fakeServer; 3036 | 3037 | sinon.fakeServerWithClock = new Server(); 3038 | 3039 | sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { 3040 | if (xhr.async) { 3041 | if (typeof setTimeout.clock == "object") { 3042 | this.clock = setTimeout.clock; 3043 | } else { 3044 | this.clock = sinon.useFakeTimers(); 3045 | this.resetClock = true; 3046 | } 3047 | 3048 | if (!this.longestTimeout) { 3049 | var clockSetTimeout = this.clock.setTimeout; 3050 | var clockSetInterval = this.clock.setInterval; 3051 | var server = this; 3052 | 3053 | this.clock.setTimeout = function (fn, timeout) { 3054 | server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); 3055 | 3056 | return clockSetTimeout.apply(this, arguments); 3057 | }; 3058 | 3059 | this.clock.setInterval = function (fn, timeout) { 3060 | server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); 3061 | 3062 | return clockSetInterval.apply(this, arguments); 3063 | }; 3064 | } 3065 | } 3066 | 3067 | return sinon.fakeServer.addRequest.call(this, xhr); 3068 | }; 3069 | 3070 | sinon.fakeServerWithClock.respond = function respond() { 3071 | var returnVal = sinon.fakeServer.respond.apply(this, arguments); 3072 | 3073 | if (this.clock) { 3074 | this.clock.tick(this.longestTimeout || 0); 3075 | this.longestTimeout = 0; 3076 | 3077 | if (this.resetClock) { 3078 | this.clock.restore(); 3079 | this.resetClock = false; 3080 | } 3081 | } 3082 | 3083 | return returnVal; 3084 | }; 3085 | 3086 | sinon.fakeServerWithClock.restore = function restore() { 3087 | if (this.clock) { 3088 | this.clock.restore(); 3089 | } 3090 | 3091 | return sinon.fakeServer.restore.apply(this, arguments); 3092 | }; 3093 | }()); 3094 | 3095 | /** 3096 | * @depend ../sinon.js 3097 | * @depend collection.js 3098 | * @depend util/fake_timers.js 3099 | * @depend util/fake_server_with_clock.js 3100 | */ 3101 | /*jslint eqeqeq: false, onevar: false, plusplus: false*/ 3102 | /*global require, module*/ 3103 | /** 3104 | * Manages fake collections as well as fake utilities such as Sinon's 3105 | * timers and fake XHR implementation in one convenient object. 3106 | * 3107 | * @author Christian Johansen (christian@cjohansen.no) 3108 | * @license BSD 3109 | * 3110 | * Copyright (c) 2010-2011 Christian Johansen 3111 | */ 3112 | 3113 | if (typeof module == "object" && typeof require == "function") { 3114 | var sinon = require("../sinon"); 3115 | sinon.extend(sinon, require("./util/fake_timers")); 3116 | } 3117 | 3118 | (function () { 3119 | var push = [].push; 3120 | 3121 | function exposeValue(sandbox, config, key, value) { 3122 | if (!value) { 3123 | return; 3124 | } 3125 | 3126 | if (config.injectInto) { 3127 | config.injectInto[key] = value; 3128 | } else { 3129 | push.call(sandbox.args, value); 3130 | } 3131 | } 3132 | 3133 | function prepareSandboxFromConfig(config) { 3134 | var sandbox = sinon.create(sinon.sandbox); 3135 | 3136 | if (config.useFakeServer) { 3137 | if (typeof config.useFakeServer == "object") { 3138 | sandbox.serverPrototype = config.useFakeServer; 3139 | } 3140 | 3141 | sandbox.useFakeServer(); 3142 | } 3143 | 3144 | if (config.useFakeTimers) { 3145 | if (typeof config.useFakeTimers == "object") { 3146 | sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); 3147 | } else { 3148 | sandbox.useFakeTimers(); 3149 | } 3150 | } 3151 | 3152 | return sandbox; 3153 | } 3154 | 3155 | sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { 3156 | useFakeTimers: function useFakeTimers() { 3157 | this.clock = sinon.useFakeTimers.apply(sinon, arguments); 3158 | 3159 | return this.add(this.clock); 3160 | }, 3161 | 3162 | serverPrototype: sinon.fakeServer, 3163 | 3164 | useFakeServer: function useFakeServer() { 3165 | var proto = this.serverPrototype || sinon.fakeServer; 3166 | 3167 | if (!proto || !proto.create) { 3168 | return null; 3169 | } 3170 | 3171 | this.server = proto.create(); 3172 | return this.add(this.server); 3173 | }, 3174 | 3175 | inject: function (obj) { 3176 | sinon.collection.inject.call(this, obj); 3177 | 3178 | if (this.clock) { 3179 | obj.clock = this.clock; 3180 | } 3181 | 3182 | if (this.server) { 3183 | obj.server = this.server; 3184 | obj.requests = this.server.requests; 3185 | } 3186 | 3187 | return obj; 3188 | }, 3189 | 3190 | create: function (config) { 3191 | if (!config) { 3192 | return sinon.create(sinon.sandbox); 3193 | } 3194 | 3195 | var sandbox = prepareSandboxFromConfig(config); 3196 | sandbox.args = sandbox.args || []; 3197 | var prop, value, exposed = sandbox.inject({}); 3198 | 3199 | if (config.properties) { 3200 | for (var i = 0, l = config.properties.length; i < l; i++) { 3201 | prop = config.properties[i]; 3202 | value = exposed[prop] || prop == "sandbox" && sandbox; 3203 | exposeValue(sandbox, config, prop, value); 3204 | } 3205 | } else { 3206 | exposeValue(sandbox, config, "sandbox", value); 3207 | } 3208 | 3209 | return sandbox; 3210 | } 3211 | }); 3212 | 3213 | sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; 3214 | 3215 | if (typeof module == "object" && typeof require == "function") { 3216 | module.exports = sinon.sandbox; 3217 | } 3218 | }()); 3219 | 3220 | /** 3221 | * @depend ../sinon.js 3222 | * @depend stub.js 3223 | * @depend mock.js 3224 | * @depend sandbox.js 3225 | */ 3226 | /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ 3227 | /*global module, require, sinon*/ 3228 | /** 3229 | * Test function, sandboxes fakes 3230 | * 3231 | * @author Christian Johansen (christian@cjohansen.no) 3232 | * @license BSD 3233 | * 3234 | * Copyright (c) 2010-2011 Christian Johansen 3235 | */ 3236 | 3237 | (function (sinon) { 3238 | var commonJSModule = typeof module == "object" && typeof require == "function"; 3239 | 3240 | if (!sinon && commonJSModule) { 3241 | sinon = require("../sinon"); 3242 | } 3243 | 3244 | if (!sinon) { 3245 | return; 3246 | } 3247 | 3248 | function test(callback) { 3249 | var type = typeof callback; 3250 | 3251 | if (type != "function") { 3252 | throw new TypeError("sinon.test needs to wrap a test function, got " + type); 3253 | } 3254 | 3255 | return function () { 3256 | var config = sinon.getConfig(sinon.config); 3257 | config.injectInto = config.injectIntoThis && this || config.injectInto; 3258 | var sandbox = sinon.sandbox.create(config); 3259 | var exception, result; 3260 | var args = Array.prototype.slice.call(arguments).concat(sandbox.args); 3261 | 3262 | try { 3263 | result = callback.apply(this, args); 3264 | } finally { 3265 | sandbox.verifyAndRestore(); 3266 | } 3267 | 3268 | return result; 3269 | }; 3270 | } 3271 | 3272 | test.config = { 3273 | injectIntoThis: true, 3274 | injectInto: null, 3275 | properties: ["spy", "stub", "mock", "clock", "server", "requests"], 3276 | useFakeTimers: true, 3277 | useFakeServer: true 3278 | }; 3279 | 3280 | if (commonJSModule) { 3281 | module.exports = test; 3282 | } else { 3283 | sinon.test = test; 3284 | } 3285 | }(typeof sinon == "object" && sinon || null)); 3286 | 3287 | /** 3288 | * @depend ../sinon.js 3289 | * @depend test.js 3290 | */ 3291 | /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ 3292 | /*global module, require, sinon*/ 3293 | /** 3294 | * Test case, sandboxes all test functions 3295 | * 3296 | * @author Christian Johansen (christian@cjohansen.no) 3297 | * @license BSD 3298 | * 3299 | * Copyright (c) 2010-2011 Christian Johansen 3300 | */ 3301 | 3302 | (function (sinon) { 3303 | var commonJSModule = typeof module == "object" && typeof require == "function"; 3304 | 3305 | if (!sinon && commonJSModule) { 3306 | sinon = require("../sinon"); 3307 | } 3308 | 3309 | if (!sinon || !Object.prototype.hasOwnProperty) { 3310 | return; 3311 | } 3312 | 3313 | function createTest(property, setUp, tearDown) { 3314 | return function () { 3315 | if (setUp) { 3316 | setUp.apply(this, arguments); 3317 | } 3318 | 3319 | var exception, result; 3320 | 3321 | try { 3322 | result = property.apply(this, arguments); 3323 | } catch (e) { 3324 | exception = e; 3325 | } 3326 | 3327 | if (tearDown) { 3328 | tearDown.apply(this, arguments); 3329 | } 3330 | 3331 | if (exception) { 3332 | throw exception; 3333 | } 3334 | 3335 | return result; 3336 | }; 3337 | } 3338 | 3339 | function testCase(tests, prefix) { 3340 | /*jsl:ignore*/ 3341 | if (!tests || typeof tests != "object") { 3342 | throw new TypeError("sinon.testCase needs an object with test functions"); 3343 | } 3344 | /*jsl:end*/ 3345 | 3346 | prefix = prefix || "test"; 3347 | var rPrefix = new RegExp("^" + prefix); 3348 | var methods = {}, testName, property, method; 3349 | var setUp = tests.setUp; 3350 | var tearDown = tests.tearDown; 3351 | 3352 | for (testName in tests) { 3353 | if (tests.hasOwnProperty(testName)) { 3354 | property = tests[testName]; 3355 | 3356 | if (/^(setUp|tearDown)$/.test(testName)) { 3357 | continue; 3358 | } 3359 | 3360 | if (typeof property == "function" && rPrefix.test(testName)) { 3361 | method = property; 3362 | 3363 | if (setUp || tearDown) { 3364 | method = createTest(property, setUp, tearDown); 3365 | } 3366 | 3367 | methods[testName] = sinon.test(method); 3368 | } else { 3369 | methods[testName] = tests[testName]; 3370 | } 3371 | } 3372 | } 3373 | 3374 | return methods; 3375 | } 3376 | 3377 | if (commonJSModule) { 3378 | module.exports = testCase; 3379 | } else { 3380 | sinon.testCase = testCase; 3381 | } 3382 | }(typeof sinon == "object" && sinon || null)); 3383 | 3384 | /** 3385 | * @depend ../sinon.js 3386 | * @depend stub.js 3387 | */ 3388 | /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ 3389 | /*global module, require, sinon*/ 3390 | /** 3391 | * Assertions matching the test spy retrieval interface. 3392 | * 3393 | * @author Christian Johansen (christian@cjohansen.no) 3394 | * @license BSD 3395 | * 3396 | * Copyright (c) 2010-2011 Christian Johansen 3397 | */ 3398 | 3399 | (function (sinon, global) { 3400 | var commonJSModule = typeof module == "object" && typeof require == "function"; 3401 | var slice = Array.prototype.slice; 3402 | var assert; 3403 | 3404 | if (!sinon && commonJSModule) { 3405 | sinon = require("../sinon"); 3406 | } 3407 | 3408 | if (!sinon) { 3409 | return; 3410 | } 3411 | 3412 | function verifyIsStub() { 3413 | var method; 3414 | 3415 | for (var i = 0, l = arguments.length; i < l; ++i) { 3416 | method = arguments[i]; 3417 | 3418 | if (!method) { 3419 | assert.fail("fake is not a spy"); 3420 | } 3421 | 3422 | if (typeof method != "function") { 3423 | assert.fail(method + " is not a function"); 3424 | } 3425 | 3426 | if (typeof method.getCall != "function") { 3427 | assert.fail(method + " is not stubbed"); 3428 | } 3429 | } 3430 | } 3431 | 3432 | function failAssertion(object, msg) { 3433 | object = object || global; 3434 | var failMethod = object.fail || assert.fail; 3435 | failMethod.call(object, msg); 3436 | } 3437 | 3438 | function mirrorPropAsAssertion(name, method, message) { 3439 | if (arguments.length == 2) { 3440 | message = method; 3441 | method = name; 3442 | } 3443 | 3444 | assert[name] = function (fake) { 3445 | verifyIsStub(fake); 3446 | 3447 | var args = slice.call(arguments, 1); 3448 | var failed = false; 3449 | 3450 | if (typeof method == "function") { 3451 | failed = !method(fake); 3452 | } else { 3453 | failed = typeof fake[method] == "function" ? 3454 | !fake[method].apply(fake, args) : !fake[method]; 3455 | } 3456 | 3457 | if (failed) { 3458 | failAssertion(this, fake.printf.apply(fake, [message].concat(args))); 3459 | } else { 3460 | assert.pass(name); 3461 | } 3462 | }; 3463 | } 3464 | 3465 | function exposedName(prefix, prop) { 3466 | return !prefix || /^fail/.test(prop) ? prop : 3467 | prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); 3468 | }; 3469 | 3470 | assert = { 3471 | failException: "AssertError", 3472 | 3473 | fail: function fail(message) { 3474 | var error = new Error(message); 3475 | error.name = this.failException || assert.failException; 3476 | 3477 | throw error; 3478 | }, 3479 | 3480 | pass: function pass(assertion) {}, 3481 | 3482 | callOrder: function assertCallOrder() { 3483 | verifyIsStub.apply(null, arguments); 3484 | var expected = "", actual = ""; 3485 | 3486 | if (!sinon.calledInOrder(arguments)) { 3487 | try { 3488 | expected = [].join.call(arguments, ", "); 3489 | actual = sinon.orderByFirstCall(slice.call(arguments)).join(", "); 3490 | } catch (e) { 3491 | // If this fails, we'll just fall back to the blank string 3492 | } 3493 | 3494 | failAssertion(this, "expected " + expected + " to be " + 3495 | "called in order but were called as " + actual); 3496 | } else { 3497 | assert.pass("callOrder"); 3498 | } 3499 | }, 3500 | 3501 | callCount: function assertCallCount(method, count) { 3502 | verifyIsStub(method); 3503 | 3504 | if (method.callCount != count) { 3505 | var msg = "expected %n to be called " + sinon.timesInWords(count) + 3506 | " but was called %c%C"; 3507 | failAssertion(this, method.printf(msg)); 3508 | } else { 3509 | assert.pass("callCount"); 3510 | } 3511 | }, 3512 | 3513 | expose: function expose(target, options) { 3514 | if (!target) { 3515 | throw new TypeError("target is null or undefined"); 3516 | } 3517 | 3518 | var o = options || {}; 3519 | var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; 3520 | var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; 3521 | 3522 | for (var method in this) { 3523 | if (method != "export" && (includeFail || !/^(fail)/.test(method))) { 3524 | target[exposedName(prefix, method)] = this[method]; 3525 | } 3526 | } 3527 | 3528 | return target; 3529 | } 3530 | }; 3531 | 3532 | mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); 3533 | mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, 3534 | "expected %n to not have been called but was called %c%C"); 3535 | mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); 3536 | mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); 3537 | mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); 3538 | mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); 3539 | mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); 3540 | mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); 3541 | mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); 3542 | mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); 3543 | mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); 3544 | mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); 3545 | mirrorPropAsAssertion("threw", "%n did not throw exception%C"); 3546 | mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); 3547 | 3548 | if (commonJSModule) { 3549 | module.exports = assert; 3550 | } else { 3551 | sinon.assert = assert; 3552 | } 3553 | }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global)); 3554 | 3555 | return sinon;}.call(typeof window != 'undefined' && window || {})); 3556 | -------------------------------------------------------------------------------- /specs/libs/sinon-ie-1.3.4.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sinon.JS 1.3.4, 2012/04/16 3 | * 4 | * @author Christian Johansen (christian@cjohansen.no) 5 | * 6 | * (The BSD License) 7 | * 8 | * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without modification, 12 | * are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * * Redistributions in binary form must reproduce the above copyright notice, 17 | * this list of conditions and the following disclaimer in the documentation 18 | * and/or other materials provided with the distribution. 19 | * * Neither the name of Christian Johansen nor the names of his contributors 20 | * may be used to endorse or promote products derived from this software 21 | * without specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | "use strict"; 36 | /*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/ 37 | /** 38 | * Helps IE run the fake timers. By defining global functions, IE allows 39 | * them to be overwritten at a later point. If these are not defined like 40 | * this, overwriting them will result in anything from an exception to browser 41 | * crash. 42 | * 43 | * If you don't require fake timers to work in IE, don't include this file. 44 | * 45 | * @author Christian Johansen (christian@cjohansen.no) 46 | * @license BSD 47 | * 48 | * Copyright (c) 2010-2011 Christian Johansen 49 | */ 50 | function setTimeout() {} 51 | function clearTimeout() {} 52 | function setInterval() {} 53 | function clearInterval() {} 54 | function Date() {} 55 | 56 | // Reassign the original functions. Now their writable attribute 57 | // should be true. Hackish, I know, but it works. 58 | setTimeout = sinon.timers.setTimeout; 59 | clearTimeout = sinon.timers.clearTimeout; 60 | setInterval = sinon.timers.setInterval; 61 | clearInterval = sinon.timers.clearInterval; 62 | Date = sinon.timers.Date; 63 | 64 | /*global sinon*/ 65 | /** 66 | * Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows 67 | * them to be overwritten at a later point. If these are not defined like 68 | * this, overwriting them will result in anything from an exception to browser 69 | * crash. 70 | * 71 | * If you don't require fake XHR to work in IE, don't include this file. 72 | * 73 | * @author Christian Johansen (christian@cjohansen.no) 74 | * @license BSD 75 | * 76 | * Copyright (c) 2010-2011 Christian Johansen 77 | */ 78 | function XMLHttpRequest() {} 79 | 80 | // Reassign the original function. Now its writable attribute 81 | // should be true. Hackish, I know, but it works. 82 | XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined; 83 | -------------------------------------------------------------------------------- /specs/matchers.js: -------------------------------------------------------------------------------- 1 | beforeEach(function(){ 2 | this.addMatchers({ 3 | toBeA: function(type){ 4 | return typeof this.actual == type; 5 | } 6 | }); 7 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload.fallback.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload.fallback", function(){ 2 | 3 | var overloadResult, 4 | fallbackResult; 5 | 6 | beforeEach(function(){ 7 | overloadResult = overload(sinon.spy()); 8 | 9 | fallbackResult = overloadResult.fallback(sinon.spy()); 10 | }); 11 | 12 | it("should return the same function as overload returned", function(){ 13 | expect(fallbackResult).toBe(overloadResult); 14 | }); 15 | 16 | describe("with no arguments", function(){ 17 | it("should throw an error", function(){ 18 | expect(function(){ 19 | overload(sinon.spy()).fallback(); 20 | }).toThrow(); 21 | }); 22 | }); 23 | 24 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | }); 9 | 10 | 11 | describe("with no arguments", function(){ 12 | 13 | it("should throw an exception", function(){ 14 | expect(function(){ 15 | overload(); 16 | }).toThrow(); 17 | }); 18 | 19 | }); 20 | 21 | 22 | describe("with one wrong argument", function(){ 23 | 24 | it("should throw an exception", function(){ 25 | expect(function(){ 26 | overload("hello"); 27 | }).toThrow(); 28 | }); 29 | 30 | }); 31 | 32 | 33 | describe("with one of two wrong argument", function(){ 34 | 35 | it("should throw an exception", function(){ 36 | expect(function(){ 37 | overload("hello", function(){ }); 38 | }).toThrow(); 39 | }); 40 | 41 | }); 42 | 43 | describe("with two wrong arguments", function(){ 44 | 45 | it("should throw an exception", function(){ 46 | expect(function(){ 47 | overload("hello", true); 48 | }).toThrow(); 49 | }); 50 | 51 | }); 52 | 53 | describe("with one function argument", function(){ 54 | 55 | beforeEach(function(){ 56 | 57 | because: { 58 | method = overload(spy); 59 | } 60 | 61 | }); 62 | 63 | it("should return a function", function(){ 64 | expect(method).toBeA("function"); 65 | }); 66 | 67 | it("the returned function should have a with method", function(){ 68 | expect(method.when).toBeA("function"); 69 | }); 70 | 71 | it("the returned function should have a fallback method", function(){ 72 | expect(method.fallback).toBeA("function"); 73 | }); 74 | 75 | describe("when calling the returned function", function(){ 76 | 77 | beforeEach(function(){ 78 | because: { 79 | method(); 80 | } 81 | }) 82 | 83 | it("should call the spy", function(){ 84 | expect(spy.callCount).toBe(1); 85 | }); 86 | 87 | }); 88 | 89 | }); 90 | 91 | describe("with one array and one function argument", function(){ 92 | 93 | beforeEach(function(){ 94 | 95 | because: { 96 | method = overload([], spy); 97 | } 98 | 99 | }); 100 | 101 | it("should return a function", function(){ 102 | expect(method).toBeA("function"); 103 | }); 104 | 105 | it("the returned function should have a with method", function(){ 106 | expect(method.when).toBeA("function"); 107 | }); 108 | 109 | it("the returned function should have a fallback method", function(){ 110 | expect(method.fallback).toBeA("function"); 111 | }); 112 | 113 | describe("when calling the returned function", function(){ 114 | 115 | beforeEach(function(){ 116 | because: { 117 | method(); 118 | } 119 | }) 120 | 121 | it("should call the spy", function(){ 122 | expect(spy.callCount).toBe(1); 123 | }); 124 | 125 | }); 126 | 127 | }); 128 | 129 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload.with.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload.with", function(){ 2 | 3 | var overloadResult, 4 | withResult; 5 | 6 | beforeEach(function(){ 7 | overloadResult = overload([String], sinon.spy()); 8 | 9 | withResult = overloadResult.when([Number], sinon.spy()); 10 | }); 11 | 12 | it("should return the same function as overload returned", function(){ 13 | expect(withResult).toBe(overloadResult); 14 | }); 15 | 16 | 17 | describe("with no arguments", function(){ 18 | it("should throw an error", function(){ 19 | expect(function(){ 20 | overload(sinon.spy()).when(); 21 | }).toThrow(); 22 | }); 23 | }); 24 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_a_Boolean_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with a Boolean type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([Boolean], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with a boolan", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method(true); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | describe("when calling the returned function with something else", function(){ 30 | 31 | beforeEach(function(){ 32 | because: { 33 | method(1); 34 | } 35 | }) 36 | 37 | it("should not call the spy", function(){ 38 | expect(spy.callCount).toBe(0); 39 | }); 40 | 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_a_Custom_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with a Custom type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | function Custom(){ 7 | 8 | } 9 | 10 | beforeEach(function () { 11 | spy = sinon.spy(); 12 | 13 | because: { 14 | method = overload([Custom], spy); 15 | } 16 | 17 | }); 18 | 19 | describe("when calling the returned function with an instance of Custom", function(){ 20 | 21 | beforeEach(function(){ 22 | because: { 23 | method(new Custom()); 24 | } 25 | }) 26 | 27 | it("should call the spy", function(){ 28 | expect(spy.callCount).toBe(1); 29 | }); 30 | 31 | }); 32 | 33 | describe("when calling the returned function with something else", function(){ 34 | 35 | beforeEach(function(){ 36 | because: { 37 | method([]); 38 | } 39 | }) 40 | 41 | it("should not call the spy", function(){ 42 | expect(spy.callCount).toBe(0); 43 | }); 44 | 45 | }); 46 | 47 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_a_Function_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with a Function type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([Function], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with a function", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method(function(){ 20 | 21 | }); 22 | } 23 | }) 24 | 25 | it("should call the spy", function(){ 26 | expect(spy.callCount).toBe(1); 27 | }); 28 | 29 | }); 30 | 31 | describe("when calling the returned function with something else", function(){ 32 | 33 | beforeEach(function(){ 34 | because: { 35 | method(1); 36 | } 37 | }) 38 | 39 | it("should not call the spy", function(){ 40 | expect(spy.callCount).toBe(0); 41 | }); 42 | 43 | }); 44 | 45 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_a_Number_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with a Number type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([Number], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with a number", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method(1); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | describe("when calling the returned function with something else", function(){ 30 | 31 | beforeEach(function(){ 32 | because: { 33 | method("hello"); 34 | } 35 | }) 36 | 37 | it("should not call the spy", function(){ 38 | expect(spy.callCount).toBe(0); 39 | }); 40 | 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_a_String_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with a String type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([String], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with a string", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method("hello"); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | describe("when calling the returned function with something else", function(){ 30 | 31 | beforeEach(function(){ 32 | because: { 33 | method(true); 34 | } 35 | }) 36 | 37 | it("should not call the spy", function(){ 38 | expect(spy.callCount).toBe(0); 39 | }); 40 | 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_an_Array_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with an Array type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([Array], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with an array", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method([]); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | describe("when calling the returned function with something else", function(){ 30 | 31 | beforeEach(function(){ 32 | because: { 33 | method(1); 34 | } 35 | }) 36 | 37 | it("should not call the spy", function(){ 38 | expect(spy.callCount).toBe(0); 39 | }); 40 | 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_an_Object_type.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with an Object type", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([Object], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function with an object", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method({}); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | describe("when calling the returned function with something else", function(){ 30 | 31 | beforeEach(function(){ 32 | because: { 33 | method([]); 34 | } 35 | }) 36 | 37 | it("should not call the spy", function(){ 38 | expect(spy.callCount).toBe(0); 39 | }); 40 | 41 | }); 42 | 43 | }); -------------------------------------------------------------------------------- /specs/when_calling_overload_with_empty_array.js: -------------------------------------------------------------------------------- 1 | describe("when calling overload with empty array", function(){ 2 | 3 | var method, 4 | spy; 5 | 6 | beforeEach(function () { 7 | spy = sinon.spy(); 8 | 9 | because: { 10 | method = overload([], spy); 11 | } 12 | 13 | }); 14 | 15 | describe("when calling the returned function", function(){ 16 | 17 | beforeEach(function(){ 18 | because: { 19 | method(); 20 | } 21 | }) 22 | 23 | it("should call the spy", function(){ 24 | expect(spy.callCount).toBe(1); 25 | }); 26 | 27 | }); 28 | 29 | }); -------------------------------------------------------------------------------- /specs/when_chaining_using_with.js: -------------------------------------------------------------------------------- 1 | describe("when chaining using with", function(){ 2 | 3 | var method, 4 | spy1, 5 | spy2, 6 | spy3, 7 | spy4, 8 | result; 9 | 10 | beforeEach(function(){ 11 | 12 | spy1 = sinon.stub().returns("result1"); 13 | spy2 = sinon.stub().returns("result2"); 14 | spy3 = sinon.stub().returns("result3"); 15 | spy4 = sinon.stub().returns("result4"); 16 | 17 | method = overload([String], spy1); 18 | method.when([Number], spy2); 19 | method.when([Array, Function], spy3); 20 | method.fallback(spy4); 21 | 22 | }); 23 | 24 | describe("when called with a string", function(){ 25 | 26 | beforeEach(function(){ 27 | result = method("hello"); 28 | }); 29 | 30 | it("should call the first function", function(){ 31 | expect(spy1.callCount).toBe(1); 32 | expect(spy2.callCount).toBe(0); 33 | expect(spy3.callCount).toBe(0); 34 | expect(spy4.callCount).toBe(0); 35 | }); 36 | 37 | it("should call the function with the passed arguments", function(){ 38 | expect(spy1.calledWithExactly("hello")).toBe(true); 39 | }); 40 | 41 | it("should return the result of the spy", function(){ 42 | expect(result).toBe("result1"); 43 | }); 44 | 45 | }); 46 | 47 | describe("when called with a number", function(){ 48 | 49 | beforeEach(function(){ 50 | result = method(1); 51 | }); 52 | 53 | it("should call the second function", function(){ 54 | expect(spy1.callCount).toBe(0); 55 | expect(spy2.callCount).toBe(1); 56 | expect(spy3.callCount).toBe(0); 57 | expect(spy4.callCount).toBe(0); 58 | }); 59 | 60 | it("should call the function with the passed arguments", function(){ 61 | expect(spy2.calledWithExactly(1)).toBe(true); 62 | }); 63 | 64 | it("should return the result of the spy", function(){ 65 | expect(result).toBe("result2"); 66 | }); 67 | }); 68 | 69 | describe("when called with an array and a function", function(){ 70 | 71 | var arg1 = [1, "hello"]; 72 | var arg2 = function(){}; 73 | 74 | beforeEach(function(){ 75 | result = method(arg1, arg2); 76 | }); 77 | 78 | it("should call the third function", function(){ 79 | expect(spy1.callCount).toBe(0); 80 | expect(spy2.callCount).toBe(0); 81 | expect(spy3.callCount).toBe(1); 82 | expect(spy4.callCount).toBe(0); 83 | }); 84 | 85 | it("should call the function with the passed arguments", function(){ 86 | expect(spy3.calledWithExactly(arg1, arg2)).toBe(true); 87 | }); 88 | 89 | it("should return the result of the spy", function(){ 90 | expect(result).toBe("result3"); 91 | }); 92 | }); 93 | 94 | describe("when called with something else", function(){ 95 | 96 | var arg1 = [1, "hello"]; 97 | 98 | beforeEach(function(){ 99 | result = method(arg1); 100 | }); 101 | 102 | it("should call the fourth function", function(){ 103 | expect(spy1.callCount).toBe(0); 104 | expect(spy2.callCount).toBe(0); 105 | expect(spy3.callCount).toBe(0); 106 | expect(spy4.callCount).toBe(1); 107 | }); 108 | 109 | it("should call the function with the passed arguments", function(){ 110 | expect(spy4.calledWithExactly(arg1)).toBe(true); 111 | }); 112 | 113 | it("should return the result of the spy", function(){ 114 | expect(result).toBe("result4"); 115 | }); 116 | }); 117 | 118 | }); -------------------------------------------------------------------------------- /specs/when_no_match_is_found.js: -------------------------------------------------------------------------------- 1 | describe("when no match is found", function(){ 2 | 3 | var fallbackSpy, 4 | shouldNotBeCalledSpy; 5 | 6 | beforeEach(function(){ 7 | 8 | fallbackSpy = sinon.spy(); 9 | shouldNotBeCalledSpy = sinon.spy(); 10 | 11 | var method = overload([Number], shouldNotBeCalledSpy).fallback(fallbackSpy); 12 | 13 | because: { 14 | method(); 15 | } 16 | }); 17 | 18 | 19 | it("should call the fallback", function(){ 20 | expect(fallbackSpy.callCount).toBe(1); 21 | }); 22 | it("should not call the overloaded function", function(){ 23 | expect(fallbackSpy.callCount).toBe(1); 24 | }); 25 | 26 | }); 27 | --------------------------------------------------------------------------------