unittests/sinon.js
branchnew-model
changeset 924 64c2eaafe5e2
parent 923 b3ee7d1b472a
child 925 28efc97b5d78
equal deleted inserted replaced
923:b3ee7d1b472a 924:64c2eaafe5e2
     1 /**
       
     2  * Sinon.JS 1.2.0, 2011/09/27
       
     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 /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
       
    37 /*global module, require, __dirname, document*/
       
    38 /**
       
    39  * Sinon core utilities. For internal use only.
       
    40  *
       
    41  * @author Christian Johansen (christian@cjohansen.no)
       
    42  * @license BSD
       
    43  *
       
    44  * Copyright (c) 2010-2011 Christian Johansen
       
    45  */
       
    46 
       
    47 var sinon = (function () {
       
    48     var div = typeof document != "undefined" && document.createElement("div");
       
    49 
       
    50     function isNode(obj) {
       
    51         var success = false;
       
    52 
       
    53         try {
       
    54             obj.appendChild(div);
       
    55             success = div.parentNode == obj;
       
    56         } catch (e) {
       
    57             return false;
       
    58         } finally {
       
    59             try {
       
    60                 obj.removeChild(div);
       
    61             } catch (e) {}
       
    62         }
       
    63 
       
    64         return success;
       
    65     }
       
    66 
       
    67     function isElement(obj) {
       
    68         return div && obj && obj.nodeType === 1 && isNode(obj);
       
    69     }
       
    70 
       
    71     return {
       
    72         wrapMethod: function wrapMethod(object, property, method) {
       
    73             if (!object) {
       
    74                 throw new TypeError("Should wrap property of object");
       
    75             }
       
    76 
       
    77             if (typeof method != "function") {
       
    78                 throw new TypeError("Method wrapper should be function");
       
    79             }
       
    80 
       
    81             var wrappedMethod = object[property];
       
    82             var type = typeof wrappedMethod;
       
    83 
       
    84             if (type != "function") {
       
    85                 throw new TypeError("Attempted to wrap " + type + " property " + property +
       
    86                                     " as function");
       
    87             }
       
    88 
       
    89             if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
       
    90                 throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
       
    91             }
       
    92 
       
    93             if (wrappedMethod.calledBefore) {
       
    94                 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
       
    95                 throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
       
    96             }
       
    97 
       
    98             var owned = object.hasOwnProperty(property);
       
    99             object[property] = method;
       
   100             method.displayName = property;
       
   101 
       
   102             method.restore = function () {
       
   103                 if(owned) {
       
   104                     object[property] = wrappedMethod;
       
   105                 } else {
       
   106                     delete object[property];
       
   107                 }
       
   108             };
       
   109 
       
   110             method.restore.sinon = true;
       
   111 
       
   112             return method;
       
   113         },
       
   114 
       
   115         extend: function extend(target) {
       
   116             for (var i = 1, l = arguments.length; i < l; i += 1) {
       
   117                 for (var prop in arguments[i]) {
       
   118                     if (arguments[i].hasOwnProperty(prop)) {
       
   119                         target[prop] = arguments[i][prop];
       
   120                     }
       
   121 
       
   122                     // DONT ENUM bug, only care about toString
       
   123                     if (arguments[i].hasOwnProperty("toString") &&
       
   124                         arguments[i].toString != target.toString) {
       
   125                         target.toString = arguments[i].toString;
       
   126                     }
       
   127                 }
       
   128             }
       
   129 
       
   130             return target;
       
   131         },
       
   132 
       
   133         create: function create(proto) {
       
   134             var F = function () {};
       
   135             F.prototype = proto;
       
   136             return new F();
       
   137         },
       
   138 
       
   139         deepEqual: function deepEqual(a, b) {
       
   140             if (typeof a != "object" || typeof b != "object") {
       
   141                 return a === b;
       
   142             }
       
   143 
       
   144             if (isElement(a) || isElement(b)) {
       
   145                 return a === b;
       
   146             }
       
   147 
       
   148             if (a === b) {
       
   149                 return true;
       
   150             }
       
   151 
       
   152             if (Object.prototype.toString.call(a) == "[object Array]") {
       
   153                 if (a.length !== b.length) {
       
   154                     return false;
       
   155                 }
       
   156 
       
   157                 for (var i = 0, l = a.length; i < l; i += 1) {
       
   158                     if (!deepEqual(a[i], b[i])) {
       
   159                         return false;
       
   160                     }
       
   161                 }
       
   162 
       
   163                 return true;
       
   164             }
       
   165 
       
   166             var prop, aLength = 0, bLength = 0;
       
   167 
       
   168             for (prop in a) {
       
   169                 aLength += 1;
       
   170 
       
   171                 if (!deepEqual(a[prop], b[prop])) {
       
   172                     return false;
       
   173                 }
       
   174             }
       
   175 
       
   176             for (prop in b) {
       
   177                 bLength += 1;
       
   178             }
       
   179 
       
   180             if (aLength != bLength) {
       
   181                 return false;
       
   182             }
       
   183 
       
   184             return true;
       
   185         },
       
   186 
       
   187         functionName: function functionName(func) {
       
   188             var name = func.displayName || func.name;
       
   189 
       
   190             // Use function decomposition as a last resort to get function
       
   191             // name. Does not rely on function decomposition to work - if it
       
   192             // doesn't debugging will be slightly less informative
       
   193             // (i.e. toString will say 'spy' rather than 'myFunc').
       
   194             if (!name) {
       
   195                 var matches = func.toString().match(/function ([^\s\(]+)/);
       
   196                 name = matches && matches[1];
       
   197             }
       
   198 
       
   199             return name;
       
   200         },
       
   201 
       
   202         functionToString: function toString() {
       
   203             if (this.getCall && this.callCount) {
       
   204                 var thisValue, prop, i = this.callCount;
       
   205 
       
   206                 while (i--) {
       
   207                     thisValue = this.getCall(i).thisValue;
       
   208 
       
   209                     for (prop in thisValue) {
       
   210                         if (thisValue[prop] === this) {
       
   211                             return prop;
       
   212                         }
       
   213                     }
       
   214                 }
       
   215             }
       
   216 
       
   217             return this.displayName || "sinon fake";
       
   218         },
       
   219 
       
   220         getConfig: function (custom) {
       
   221             var config = {};
       
   222             custom = custom || {};
       
   223             var defaults = sinon.defaultConfig;
       
   224 
       
   225             for (var prop in defaults) {
       
   226                 if (defaults.hasOwnProperty(prop)) {
       
   227                     config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
       
   228                 }
       
   229             }
       
   230 
       
   231             return config;
       
   232         },
       
   233 
       
   234         format: function (val) {
       
   235             return "" + val;
       
   236         },
       
   237 
       
   238         defaultConfig: {
       
   239             injectIntoThis: true,
       
   240             injectInto: null,
       
   241             properties: ["spy", "stub", "mock", "clock", "server", "requests"],
       
   242             useFakeTimers: true,
       
   243             useFakeServer: true
       
   244         },
       
   245 
       
   246         timesInWords: function timesInWords(count) {
       
   247             return count == 1 && "once" ||
       
   248                 count == 2 && "twice" ||
       
   249                 count == 3 && "thrice" ||
       
   250                 (count || 0) + " times";
       
   251         },
       
   252 
       
   253         calledInOrder: function (spies) {
       
   254             for (var i = 1, l = spies.length; i < l; i++) {
       
   255                 if (!spies[i - 1].calledBefore(spies[i])) {
       
   256                     return false;
       
   257                 }
       
   258             }
       
   259 
       
   260             return true;
       
   261         },
       
   262 
       
   263         orderByFirstCall: function (spies) {
       
   264             return spies.sort(function (a, b) {
       
   265                 // uuid, won't ever be equal
       
   266                 return a.getCall(0).callId < b.getCall(0).callId ? -1 : 1;
       
   267             });
       
   268         }
       
   269     };
       
   270 }());
       
   271 
       
   272 if (typeof module == "object" && typeof require == "function") {
       
   273     module.exports = sinon;
       
   274     module.exports.spy = require("./sinon/spy");
       
   275     module.exports.stub = require("./sinon/stub");
       
   276     module.exports.mock = require("./sinon/mock");
       
   277     module.exports.collection = require("./sinon/collection");
       
   278     module.exports.assert = require("./sinon/assert");
       
   279     module.exports.sandbox = require("./sinon/sandbox");
       
   280     module.exports.test = require("./sinon/test");
       
   281     module.exports.testCase = require("./sinon/test_case");
       
   282     module.exports.assert = require("./sinon/assert");
       
   283 }
       
   284 
       
   285 /* @depend ../sinon.js */
       
   286 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
       
   287 /*global module, require, sinon*/
       
   288 /**
       
   289  * Spy functions
       
   290  *
       
   291  * @author Christian Johansen (christian@cjohansen.no)
       
   292  * @license BSD
       
   293  *
       
   294  * Copyright (c) 2010-2011 Christian Johansen
       
   295  */
       
   296 
       
   297 (function (sinon) {
       
   298     var commonJSModule = typeof module == "object" && typeof require == "function";
       
   299     var spyCall;
       
   300     var callId = 0;
       
   301     var push = [].push;
       
   302 
       
   303     if (!sinon && commonJSModule) {
       
   304         sinon = require("../sinon");
       
   305     }
       
   306 
       
   307     if (!sinon) {
       
   308         return;
       
   309     }
       
   310 
       
   311     function spy(object, property) {
       
   312         if (!property && typeof object == "function") {
       
   313             return spy.create(object);
       
   314         }
       
   315 
       
   316         if (!object || !property) {
       
   317             return spy.create(function () {});
       
   318         }
       
   319 
       
   320         var method = object[property];
       
   321         return sinon.wrapMethod(object, property, spy.create(method));
       
   322     }
       
   323 
       
   324     sinon.extend(spy, (function () {
       
   325         var slice = Array.prototype.slice;
       
   326 
       
   327         function delegateToCalls(api, method, matchAny, actual, notCalled) {
       
   328             api[method] = function () {
       
   329                 if (!this.called) {
       
   330                     return !!notCalled;
       
   331                 }
       
   332 
       
   333                 var currentCall;
       
   334                 var matches = 0;
       
   335 
       
   336                 for (var i = 0, l = this.callCount; i < l; i += 1) {
       
   337                     currentCall = this.getCall(i);
       
   338 
       
   339                     if (currentCall[actual || method].apply(currentCall, arguments)) {
       
   340                         matches += 1;
       
   341 
       
   342                         if (matchAny) {
       
   343                             return true;
       
   344                         }
       
   345                     }
       
   346                 }
       
   347 
       
   348                 return matches === this.callCount;
       
   349             };
       
   350         }
       
   351 
       
   352         function matchingFake(fakes, args, strict) {
       
   353             if (!fakes) {
       
   354                 return;
       
   355             }
       
   356 
       
   357             var alen = args.length;
       
   358 
       
   359             for (var i = 0, l = fakes.length; i < l; i++) {
       
   360                 if (fakes[i].matches(args, strict)) {
       
   361                     return fakes[i];
       
   362                 }
       
   363             }
       
   364         }
       
   365 
       
   366         var uuid = 0;
       
   367 
       
   368         // Public API
       
   369         var spyApi = {
       
   370             reset: function () {
       
   371                 this.called = false;
       
   372                 this.calledOnce = false;
       
   373                 this.calledTwice = false;
       
   374                 this.calledThrice = false;
       
   375                 this.callCount = 0;
       
   376                 this.args = [];
       
   377                 this.returnValues = [];
       
   378                 this.thisValues = [];
       
   379                 this.exceptions = [];
       
   380                 this.callIds = [];
       
   381             },
       
   382 
       
   383             create: function create(func) {
       
   384                 var name;
       
   385 
       
   386                 if (typeof func != "function") {
       
   387                     func = function () {};
       
   388                 } else {
       
   389                     name = sinon.functionName(func);
       
   390                 }
       
   391 
       
   392                 function proxy() {
       
   393                     return proxy.invoke(func, this, slice.call(arguments));
       
   394                 }
       
   395 
       
   396                 sinon.extend(proxy, spy);
       
   397                 delete proxy.create;
       
   398                 sinon.extend(proxy, func);
       
   399 
       
   400                 proxy.reset();
       
   401                 proxy.prototype = func.prototype;
       
   402                 proxy.displayName = name || "spy";
       
   403                 proxy.toString = sinon.functionToString;
       
   404                 proxy._create = sinon.spy.create;
       
   405                 proxy.id = "spy#" + uuid++;
       
   406 
       
   407                 return proxy;
       
   408             },
       
   409 
       
   410             invoke: function invoke(func, thisValue, args) {
       
   411                 var matching = matchingFake(this.fakes, args);
       
   412                 var exception, returnValue;
       
   413                 this.called = true;
       
   414                 this.callCount += 1;
       
   415                 this.calledOnce = this.callCount == 1;
       
   416                 this.calledTwice = this.callCount == 2;
       
   417                 this.calledThrice = this.callCount == 3;
       
   418                 push.call(this.thisValues, thisValue);
       
   419                 push.call(this.args, args);
       
   420                 push.call(this.callIds, callId++);
       
   421 
       
   422                 try {
       
   423                     if (matching) {
       
   424                         returnValue = matching.invoke(func, thisValue, args);
       
   425                     } else {
       
   426                         returnValue = (this.func || func).apply(thisValue, args);
       
   427                     }
       
   428                 } catch (e) {
       
   429                     push.call(this.returnValues, undefined);
       
   430                     exception = e;
       
   431                     throw e;
       
   432                 } finally {
       
   433                     push.call(this.exceptions, exception);
       
   434                 }
       
   435 
       
   436                 push.call(this.returnValues, returnValue);
       
   437 
       
   438                 return returnValue;
       
   439             },
       
   440 
       
   441             getCall: function getCall(i) {
       
   442                 if (i < 0 || i >= this.callCount) {
       
   443                     return null;
       
   444                 }
       
   445 
       
   446                 return spyCall.create(this, this.thisValues[i], this.args[i],
       
   447                                       this.returnValues[i], this.exceptions[i],
       
   448                                       this.callIds[i]);
       
   449             },
       
   450 
       
   451             calledBefore: function calledBefore(spyFn) {
       
   452                 if (!this.called) {
       
   453                     return false;
       
   454                 }
       
   455 
       
   456                 if (!spyFn.called) {
       
   457                     return true;
       
   458                 }
       
   459 
       
   460                 return this.callIds[0] < spyFn.callIds[0];
       
   461             },
       
   462 
       
   463             calledAfter: function calledAfter(spyFn) {
       
   464                 if (!this.called || !spyFn.called) {
       
   465                     return false;
       
   466                 }
       
   467 
       
   468                 return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
       
   469             },
       
   470 
       
   471             withArgs: function () {
       
   472                 var args = slice.call(arguments);
       
   473 
       
   474                 if (this.fakes) {
       
   475                     var match = matchingFake(this.fakes, args, true);
       
   476 
       
   477                     if (match) {
       
   478                         return match;
       
   479                     }
       
   480                 } else {
       
   481                     this.fakes = [];
       
   482                 }
       
   483 
       
   484                 var original = this;
       
   485                 var fake = this._create();
       
   486                 fake.matchingAguments = args;
       
   487                 push.call(this.fakes, fake);
       
   488 
       
   489                 fake.withArgs = function () {
       
   490                     return original.withArgs.apply(original, arguments);
       
   491                 };
       
   492 
       
   493                 return fake;
       
   494             },
       
   495 
       
   496             matches: function (args, strict) {
       
   497                 var margs = this.matchingAguments;
       
   498 
       
   499                 if (margs.length <= args.length &&
       
   500                     sinon.deepEqual(margs, args.slice(0, margs.length))) {
       
   501                     return !strict || margs.length == args.length;
       
   502                 }
       
   503             },
       
   504 
       
   505             printf: function (format) {
       
   506                 var spy = this;
       
   507                 var args = [].slice.call(arguments, 1);
       
   508                 var formatter;
       
   509 
       
   510                 return (format || "").replace(/%(.)/g, function (match, specifyer) {
       
   511                     formatter = spyApi.formatters[specifyer];
       
   512 
       
   513                     if (typeof formatter == "function") {
       
   514                         return formatter.call(null, spy, args);
       
   515                     } else if (!isNaN(parseInt(specifyer), 10)) {
       
   516                         return sinon.format(args[specifyer - 1]);
       
   517                     }
       
   518 
       
   519                     return "%" + specifyer;
       
   520                 });
       
   521             }
       
   522         };
       
   523 
       
   524         delegateToCalls(spyApi, "calledOn", true);
       
   525         delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn");
       
   526         delegateToCalls(spyApi, "calledWith", true);
       
   527         delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith");
       
   528         delegateToCalls(spyApi, "calledWithExactly", true);
       
   529         delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly");
       
   530         delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith", true);
       
   531         delegateToCalls(spyApi, "threw", true);
       
   532         delegateToCalls(spyApi, "alwaysThrew", false, "threw");
       
   533         delegateToCalls(spyApi, "returned", true);
       
   534         delegateToCalls(spyApi, "alwaysReturned", false, "returned");
       
   535         delegateToCalls(spyApi, "calledWithNew", true);
       
   536         delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew");
       
   537 
       
   538         spyApi.formatters = {
       
   539             "c": function (spy) {
       
   540                 return sinon.timesInWords(spy.callCount);
       
   541             },
       
   542 
       
   543             "n": function (spy) {
       
   544                 return spy.toString();
       
   545             },
       
   546 
       
   547             "C": function (spy) {
       
   548                 var calls = [];
       
   549 
       
   550                 for (var i = 0, l = spy.callCount; i < l; ++i) {
       
   551                     push.call(calls, "    " + spy.getCall(i).toString());
       
   552                 }
       
   553 
       
   554                 return calls.length > 0 ? "\n" + calls.join("\n") : "";
       
   555             },
       
   556 
       
   557             "t": function (spy) {
       
   558                 var objects = [];
       
   559 
       
   560                 for (var i = 0, l = spy.callCount; i < l; ++i) {
       
   561                     push.call(objects, sinon.format(spy.thisValues[i]));
       
   562                 }
       
   563 
       
   564                 return objects.join(", ");
       
   565             },
       
   566 
       
   567             "*": function (spy, args) {
       
   568                 return args.join(", ");
       
   569             }
       
   570         };
       
   571 
       
   572         return spyApi;
       
   573     }()));
       
   574 
       
   575     spyCall = (function () {
       
   576         return {
       
   577             create: function create(spy, thisValue, args, returnValue, exception, id) {
       
   578                 var proxyCall = sinon.create(spyCall);
       
   579                 delete proxyCall.create;
       
   580                 proxyCall.proxy = spy;
       
   581                 proxyCall.thisValue = thisValue;
       
   582                 proxyCall.args = args;
       
   583                 proxyCall.returnValue = returnValue;
       
   584                 proxyCall.exception = exception;
       
   585                 proxyCall.callId = typeof id == "number" && id || callId++;
       
   586 
       
   587                 return proxyCall;
       
   588             },
       
   589 
       
   590             calledOn: function calledOn(thisValue) {
       
   591                 return this.thisValue === thisValue;
       
   592             },
       
   593 
       
   594             calledWith: function calledWith() {
       
   595                 for (var i = 0, l = arguments.length; i < l; i += 1) {
       
   596                     if (!sinon.deepEqual(arguments[i], this.args[i])) {
       
   597                         return false;
       
   598                     }
       
   599                 }
       
   600 
       
   601                 return true;
       
   602             },
       
   603 
       
   604             calledWithExactly: function calledWithExactly() {
       
   605                 return arguments.length == this.args.length &&
       
   606                     this.calledWith.apply(this, arguments);
       
   607             },
       
   608 
       
   609             notCalledWith: function notCalledWith() {
       
   610                 for (var i = 0, l = arguments.length; i < l; i += 1) {
       
   611                     if (!sinon.deepEqual(arguments[i], this.args[i])) {
       
   612                         return true;
       
   613                     }
       
   614                 }
       
   615                 return false;
       
   616             },
       
   617 
       
   618             returned: function returned(value) {
       
   619                 return this.returnValue === value;
       
   620             },
       
   621 
       
   622             threw: function threw(error) {
       
   623                 if (typeof error == "undefined" || !this.exception) {
       
   624                     return !!this.exception;
       
   625                 }
       
   626 
       
   627                 if (typeof error == "string") {
       
   628                     return this.exception.name == error;
       
   629                 }
       
   630 
       
   631                 return this.exception === error;
       
   632             },
       
   633 
       
   634             calledWithNew: function calledWithNew(thisValue) {
       
   635                 return this.thisValue instanceof this.proxy;
       
   636             },
       
   637 
       
   638             calledBefore: function (other) {
       
   639                 return this.callId < other.callId;
       
   640             },
       
   641 
       
   642             calledAfter: function (other) {
       
   643                 return this.callId > other.callId;
       
   644             },
       
   645 
       
   646             toString: function () {
       
   647                 var callStr = this.proxy.toString() + "(";
       
   648                 var args = [];
       
   649 
       
   650                 for (var i = 0, l = this.args.length; i < l; ++i) {
       
   651                     push.call(args, sinon.format(this.args[i]));
       
   652                 }
       
   653 
       
   654                 callStr = callStr + args.join(", ") + ")";
       
   655 
       
   656                 if (typeof this.returnValue != "undefined") {
       
   657                     callStr += " => " + sinon.format(this.returnValue);
       
   658                 }
       
   659 
       
   660                 if (this.exception) {
       
   661                     callStr += " !" + this.exception.name;
       
   662 
       
   663                     if (this.exception.message) {
       
   664                         callStr += "(" + this.exception.message + ")";
       
   665                     }
       
   666                 }
       
   667 
       
   668                 return callStr;
       
   669             }
       
   670         };
       
   671     }());
       
   672 
       
   673     spy.spyCall = spyCall;
       
   674 
       
   675     // This steps outside the module sandbox and will be removed
       
   676     sinon.spyCall = spyCall;
       
   677 
       
   678     if (commonJSModule) {
       
   679         module.exports = spy;
       
   680     } else {
       
   681         sinon.spy = spy;
       
   682     }
       
   683 }(typeof sinon == "object" && sinon || null));
       
   684 
       
   685 /**
       
   686  * @depend ../sinon.js
       
   687  * @depend spy.js
       
   688  */
       
   689 /*jslint eqeqeq: false, onevar: false*/
       
   690 /*global module, require, sinon*/
       
   691 /**
       
   692  * Stub functions
       
   693  *
       
   694  * @author Christian Johansen (christian@cjohansen.no)
       
   695  * @license BSD
       
   696  *
       
   697  * Copyright (c) 2010-2011 Christian Johansen
       
   698  */
       
   699 
       
   700 (function (sinon) {
       
   701     var commonJSModule = typeof module == "object" && typeof require == "function";
       
   702 
       
   703     if (!sinon && commonJSModule) {
       
   704         sinon = require("../sinon");
       
   705     }
       
   706 
       
   707     if (!sinon) {
       
   708         return;
       
   709     }
       
   710 
       
   711     function stub(object, property, func) {
       
   712         if (!!func && typeof func != "function") {
       
   713             throw new TypeError("Custom stub should be function");
       
   714         }
       
   715 
       
   716         var wrapper;
       
   717 
       
   718         if (func) {
       
   719             wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
       
   720         } else {
       
   721             wrapper = stub.create();
       
   722         }
       
   723 
       
   724         if (!object && !property) {
       
   725             return sinon.stub.create();
       
   726         }
       
   727 
       
   728         if (!property && !!object && typeof object == "object") {
       
   729             for (var prop in object) {
       
   730                 if (object.hasOwnProperty(prop) && typeof object[prop] == "function") {
       
   731                     stub(object, prop);
       
   732                 }
       
   733             }
       
   734 
       
   735             return object;
       
   736         }
       
   737 
       
   738         return sinon.wrapMethod(object, property, wrapper);
       
   739     }
       
   740 
       
   741     function getCallback(stub, args) {
       
   742         if (stub.callArgAt < 0) {
       
   743             for (var i = 0, l = args.length; i < l; ++i) {
       
   744                 if (!stub.callArgProp && typeof args[i] == "function") {
       
   745                     return args[i];
       
   746                 }
       
   747 
       
   748                 if (stub.callArgProp && args[i] &&
       
   749                     typeof args[i][stub.callArgProp] == "function") {
       
   750                     return args[i][stub.callArgProp];
       
   751                 }
       
   752             }
       
   753 
       
   754             return null;
       
   755         }
       
   756 
       
   757         return args[stub.callArgAt];
       
   758     }
       
   759 
       
   760     var join = Array.prototype.join;
       
   761 
       
   762     function getCallbackError(stub, func, args) {
       
   763         if (stub.callArgAt < 0) {
       
   764             var msg;
       
   765 
       
   766             if (stub.callArgProp) {
       
   767                 msg = sinon.functionName(stub) +
       
   768                     " expected to yield to '" + stub.callArgProp +
       
   769                     "', but no object with such a property was passed."
       
   770             } else {
       
   771                 msg = sinon.functionName(stub) +
       
   772                             " expected to yield, but no callback was passed."
       
   773             }
       
   774 
       
   775             if (args.length > 0) {
       
   776                 msg += " Received [" + join.call(args, ", ") + "]";
       
   777             }
       
   778 
       
   779             return msg;
       
   780         }
       
   781 
       
   782         return "argument at index " + stub.callArgAt + " is not a function: " + func;
       
   783     }
       
   784 
       
   785     function callCallback(stub, args) {
       
   786         if (typeof stub.callArgAt == "number") {
       
   787             var func = getCallback(stub, args);
       
   788 
       
   789             if (typeof func != "function") {
       
   790                 throw new TypeError(getCallbackError(stub, func, args));
       
   791             }
       
   792 
       
   793             func.apply(null, stub.callbackArguments);
       
   794         }
       
   795     }
       
   796 
       
   797     var uuid = 0;
       
   798 
       
   799     sinon.extend(stub, (function () {
       
   800         var slice = Array.prototype.slice;
       
   801 
       
   802         function throwsException(error, message) {
       
   803             if (typeof error == "string") {
       
   804                 this.exception = new Error(message || "");
       
   805                 this.exception.name = error;
       
   806             } else if (!error) {
       
   807                 this.exception = new Error("Error");
       
   808             } else {
       
   809                 this.exception = error;
       
   810             }
       
   811             
       
   812             return this;
       
   813         }
       
   814 
       
   815         return {
       
   816             create: function create() {
       
   817                 var functionStub = function () {
       
   818                     if (functionStub.exception) {
       
   819                         throw functionStub.exception;
       
   820                     }
       
   821 
       
   822                     callCallback(functionStub, arguments);
       
   823 
       
   824                     return functionStub.returnValue;
       
   825                 };
       
   826 
       
   827                 functionStub.id = "stub#" + uuid++;
       
   828                 var orig = functionStub;
       
   829                 functionStub = sinon.spy.create(functionStub);
       
   830                 functionStub.func = orig;
       
   831 
       
   832                 sinon.extend(functionStub, stub);
       
   833                 functionStub._create = sinon.stub.create;
       
   834                 functionStub.displayName = "stub";
       
   835                 functionStub.toString = sinon.functionToString;
       
   836 
       
   837                 return functionStub;
       
   838             },
       
   839 
       
   840             returns: function returns(value) {
       
   841                 this.returnValue = value;
       
   842 
       
   843                 return this;
       
   844             },
       
   845 
       
   846             "throws": throwsException,
       
   847             throwsException: throwsException,
       
   848 
       
   849             callsArg: function callsArg(pos) {
       
   850                 if (typeof pos != "number") {
       
   851                     throw new TypeError("argument index is not number");
       
   852                 }
       
   853 
       
   854                 this.callArgAt = pos;
       
   855                 this.callbackArguments = [];
       
   856 
       
   857                 return this;
       
   858             },
       
   859 
       
   860             callsArgWith: function callsArgWith(pos) {
       
   861                 if (typeof pos != "number") {
       
   862                     throw new TypeError("argument index is not number");
       
   863                 }
       
   864 
       
   865                 this.callArgAt = pos;
       
   866                 this.callbackArguments = slice.call(arguments, 1);
       
   867 
       
   868                 return this;
       
   869             },
       
   870 
       
   871             yields: function () {
       
   872                 this.callArgAt = -1;
       
   873                 this.callbackArguments = slice.call(arguments, 0);
       
   874 
       
   875                 return this;
       
   876             },
       
   877 
       
   878             yieldsTo: function (prop) {
       
   879                 this.callArgAt = -1;
       
   880                 this.callArgProp = prop;
       
   881                 this.callbackArguments = slice.call(arguments, 1);
       
   882 
       
   883                 return this;
       
   884             }
       
   885         };
       
   886     }()));
       
   887 
       
   888     if (commonJSModule) {
       
   889         module.exports = stub;
       
   890     } else {
       
   891         sinon.stub = stub;
       
   892     }
       
   893 }(typeof sinon == "object" && sinon || null));
       
   894 
       
   895 /**
       
   896  * @depend ../sinon.js
       
   897  * @depend stub.js
       
   898  */
       
   899 /*jslint eqeqeq: false, onevar: false, nomen: false*/
       
   900 /*global module, require, sinon*/
       
   901 /**
       
   902  * Mock functions.
       
   903  *
       
   904  * @author Christian Johansen (christian@cjohansen.no)
       
   905  * @license BSD
       
   906  *
       
   907  * Copyright (c) 2010-2011 Christian Johansen
       
   908  */
       
   909 
       
   910 (function (sinon) {
       
   911     var commonJSModule = typeof module == "object" && typeof require == "function";
       
   912     var push = [].push;
       
   913 
       
   914     if (!sinon && commonJSModule) {
       
   915         sinon = require("../sinon");
       
   916     }
       
   917 
       
   918     if (!sinon) {
       
   919         return;
       
   920     }
       
   921 
       
   922     function mock(object) {
       
   923         if (!object) {
       
   924             return sinon.expectation.create("Anonymous mock");
       
   925         }
       
   926 
       
   927         return mock.create(object);
       
   928     }
       
   929 
       
   930     sinon.mock = mock;
       
   931 
       
   932     sinon.extend(mock, (function () {
       
   933         function each(collection, callback) {
       
   934             if (!collection) {
       
   935                 return;
       
   936             }
       
   937 
       
   938             for (var i = 0, l = collection.length; i < l; i += 1) {
       
   939                 callback(collection[i]);
       
   940             }
       
   941         }
       
   942 
       
   943         return {
       
   944             create: function create(object) {
       
   945                 if (!object) {
       
   946                     throw new TypeError("object is null");
       
   947                 }
       
   948 
       
   949                 var mockObject = sinon.extend({}, mock);
       
   950                 mockObject.object = object;
       
   951                 delete mockObject.create;
       
   952 
       
   953                 return mockObject;
       
   954             },
       
   955 
       
   956             expects: function expects(method) {
       
   957                 if (!method) {
       
   958                     throw new TypeError("method is falsy");
       
   959                 }
       
   960 
       
   961                 if (!this.expectations) {
       
   962                     this.expectations = {};
       
   963                     this.proxies = [];
       
   964                 }
       
   965 
       
   966                 if (!this.expectations[method]) {
       
   967                     this.expectations[method] = [];
       
   968                     var mockObject = this;
       
   969 
       
   970                     sinon.wrapMethod(this.object, method, function () {
       
   971                         return mockObject.invokeMethod(method, this, arguments);
       
   972                     });
       
   973 
       
   974                     push.call(this.proxies, method);
       
   975                 }
       
   976 
       
   977                 var expectation = sinon.expectation.create(method);
       
   978                 push.call(this.expectations[method], expectation);
       
   979 
       
   980                 return expectation;
       
   981             },
       
   982 
       
   983             restore: function restore() {
       
   984                 var object = this.object;
       
   985 
       
   986                 each(this.proxies, function (proxy) {
       
   987                     if (typeof object[proxy].restore == "function") {
       
   988                         object[proxy].restore();
       
   989                     }
       
   990                 });
       
   991             },
       
   992 
       
   993             verify: function verify() {
       
   994                 var expectations = this.expectations || {};
       
   995                 var messages = [], met = [];
       
   996 
       
   997                 each(this.proxies, function (proxy) {
       
   998                     each(expectations[proxy], function (expectation) {
       
   999                         if (!expectation.met()) {
       
  1000                             push.call(messages, expectation.toString());
       
  1001                         } else {
       
  1002                             push.call(met, expectation.toString());
       
  1003                         }
       
  1004                     });
       
  1005                 });
       
  1006 
       
  1007                 this.restore();
       
  1008 
       
  1009                 if (messages.length > 0) {
       
  1010                     sinon.expectation.fail(messages.concat(met).join("\n"));
       
  1011                 }
       
  1012 
       
  1013                 return true;
       
  1014             },
       
  1015 
       
  1016             invokeMethod: function invokeMethod(method, thisValue, args) {
       
  1017                 var expectations = this.expectations && this.expectations[method];
       
  1018                 var length = expectations && expectations.length || 0;
       
  1019 
       
  1020                 for (var i = 0; i < length; i += 1) {
       
  1021                     if (!expectations[i].met() &&
       
  1022                         expectations[i].allowsCall(thisValue, args)) {
       
  1023                         return expectations[i].apply(thisValue, args);
       
  1024                     }
       
  1025                 }
       
  1026 
       
  1027                 var messages = [];
       
  1028 
       
  1029                 for (i = 0; i < length; i += 1) {
       
  1030                     push.call(messages, "    " + expectations[i].toString());
       
  1031                 }
       
  1032 
       
  1033                 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
       
  1034                     proxy: method,
       
  1035                     args: args
       
  1036                 }));
       
  1037 
       
  1038                 sinon.expectation.fail(messages.join("\n"));
       
  1039             }
       
  1040         };
       
  1041     }()));
       
  1042 
       
  1043     var times = sinon.timesInWords;
       
  1044 
       
  1045     sinon.expectation = (function () {
       
  1046         var slice = Array.prototype.slice;
       
  1047         var _invoke = sinon.spy.invoke;
       
  1048 
       
  1049         function callCountInWords(callCount) {
       
  1050             if (callCount == 0) {
       
  1051                 return "never called";
       
  1052             } else {
       
  1053                 return "called " + times(callCount);
       
  1054             }
       
  1055         }
       
  1056 
       
  1057         function expectedCallCountInWords(expectation) {
       
  1058             var min = expectation.minCalls;
       
  1059             var max = expectation.maxCalls;
       
  1060 
       
  1061             if (typeof min == "number" && typeof max == "number") {
       
  1062                 var str = times(min);
       
  1063 
       
  1064                 if (min != max) {
       
  1065                     str = "at least " + str + " and at most " + times(max);
       
  1066                 }
       
  1067 
       
  1068                 return str;
       
  1069             }
       
  1070 
       
  1071             if (typeof min == "number") {
       
  1072                 return "at least " + times(min);
       
  1073             }
       
  1074 
       
  1075             return "at most " + times(max);
       
  1076         }
       
  1077 
       
  1078         function receivedMinCalls(expectation) {
       
  1079             var hasMinLimit = typeof expectation.minCalls == "number";
       
  1080             return !hasMinLimit || expectation.callCount >= expectation.minCalls;
       
  1081         }
       
  1082 
       
  1083         function receivedMaxCalls(expectation) {
       
  1084             if (typeof expectation.maxCalls != "number") {
       
  1085                 return false;
       
  1086             }
       
  1087 
       
  1088             return expectation.callCount == expectation.maxCalls;
       
  1089         }
       
  1090 
       
  1091         return {
       
  1092             minCalls: 1,
       
  1093             maxCalls: 1,
       
  1094 
       
  1095             create: function create(methodName) {
       
  1096                 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
       
  1097                 delete expectation.create;
       
  1098                 expectation.method = methodName;
       
  1099 
       
  1100                 return expectation;
       
  1101             },
       
  1102 
       
  1103             invoke: function invoke(func, thisValue, args) {
       
  1104                 this.verifyCallAllowed(thisValue, args);
       
  1105 
       
  1106                 return _invoke.apply(this, arguments);
       
  1107             },
       
  1108 
       
  1109             atLeast: function atLeast(num) {
       
  1110                 if (typeof num != "number") {
       
  1111                     throw new TypeError("'" + num + "' is not number");
       
  1112                 }
       
  1113 
       
  1114                 if (!this.limitsSet) {
       
  1115                     this.maxCalls = null;
       
  1116                     this.limitsSet = true;
       
  1117                 }
       
  1118 
       
  1119                 this.minCalls = num;
       
  1120 
       
  1121                 return this;
       
  1122             },
       
  1123 
       
  1124             atMost: function atMost(num) {
       
  1125                 if (typeof num != "number") {
       
  1126                     throw new TypeError("'" + num + "' is not number");
       
  1127                 }
       
  1128 
       
  1129                 if (!this.limitsSet) {
       
  1130                     this.minCalls = null;
       
  1131                     this.limitsSet = true;
       
  1132                 }
       
  1133 
       
  1134                 this.maxCalls = num;
       
  1135 
       
  1136                 return this;
       
  1137             },
       
  1138 
       
  1139             never: function never() {
       
  1140                 return this.exactly(0);
       
  1141             },
       
  1142 
       
  1143             once: function once() {
       
  1144                 return this.exactly(1);
       
  1145             },
       
  1146 
       
  1147             twice: function twice() {
       
  1148                 return this.exactly(2);
       
  1149             },
       
  1150 
       
  1151             thrice: function thrice() {
       
  1152                 return this.exactly(3);
       
  1153             },
       
  1154 
       
  1155             exactly: function exactly(num) {
       
  1156                 if (typeof num != "number") {
       
  1157                     throw new TypeError("'" + num + "' is not a number");
       
  1158                 }
       
  1159 
       
  1160                 this.atLeast(num);
       
  1161                 return this.atMost(num);
       
  1162             },
       
  1163 
       
  1164             met: function met() {
       
  1165                 return !this.failed && receivedMinCalls(this);
       
  1166             },
       
  1167 
       
  1168             verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
       
  1169                 if (receivedMaxCalls(this)) {
       
  1170                     this.failed = true;
       
  1171                     sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
       
  1172                 }
       
  1173 
       
  1174                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
       
  1175                     sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
       
  1176                         this.expectedThis);
       
  1177                 }
       
  1178 
       
  1179                 if (!("expectedArguments" in this)) {
       
  1180                     return;
       
  1181                 }
       
  1182 
       
  1183                 if (!args || args.length === 0) {
       
  1184                     sinon.expectation.fail(this.method + " received no arguments, expected " +
       
  1185                         this.expectedArguments.join());
       
  1186                 }
       
  1187 
       
  1188                 if (args.length < this.expectedArguments.length) {
       
  1189                     sinon.expectation.fail(this.method + " received too few arguments (" + args.join() +
       
  1190                         "), expected " + this.expectedArguments.join());
       
  1191                 }
       
  1192 
       
  1193                 if (this.expectsExactArgCount &&
       
  1194                     args.length != this.expectedArguments.length) {
       
  1195                     sinon.expectation.fail(this.method + " received too many arguments (" + args.join() +
       
  1196                         "), expected " + this.expectedArguments.join());
       
  1197                 }
       
  1198 
       
  1199                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
       
  1200                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
       
  1201                         sinon.expectation.fail(this.method + " received wrong arguments (" + args.join() +
       
  1202                             "), expected " + this.expectedArguments.join());
       
  1203                     }
       
  1204                 }
       
  1205             },
       
  1206 
       
  1207             allowsCall: function allowsCall(thisValue, args) {
       
  1208                 if (this.met()) {
       
  1209                     return false;
       
  1210                 }
       
  1211 
       
  1212                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
       
  1213                     return false;
       
  1214                 }
       
  1215 
       
  1216                 if (!("expectedArguments" in this)) {
       
  1217                     return true;
       
  1218                 }
       
  1219 
       
  1220                 args = args || [];
       
  1221 
       
  1222                 if (args.length < this.expectedArguments.length) {
       
  1223                     return false;
       
  1224                 }
       
  1225 
       
  1226                 if (this.expectsExactArgCount &&
       
  1227                     args.length != this.expectedArguments.length) {
       
  1228                     return false;
       
  1229                 }
       
  1230 
       
  1231                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
       
  1232                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
       
  1233                         return false;
       
  1234                     }
       
  1235                 }
       
  1236 
       
  1237                 return true;
       
  1238             },
       
  1239 
       
  1240             withArgs: function withArgs() {
       
  1241                 this.expectedArguments = slice.call(arguments);
       
  1242                 return this;
       
  1243             },
       
  1244 
       
  1245             withExactArgs: function withExactArgs() {
       
  1246                 this.withArgs.apply(this, arguments);
       
  1247                 this.expectsExactArgCount = true;
       
  1248                 return this;
       
  1249             },
       
  1250 
       
  1251             on: function on(thisValue) {
       
  1252                 this.expectedThis = thisValue;
       
  1253                 return this;
       
  1254             },
       
  1255 
       
  1256             toString: function () {
       
  1257                 var args = (this.expectedArguments || []).slice();
       
  1258 
       
  1259                 if (!this.expectsExactArgCount) {
       
  1260                     push.call(args, "[...]");
       
  1261                 }
       
  1262 
       
  1263                 var callStr = sinon.spyCall.toString.call({
       
  1264                     proxy: this.method, args: args
       
  1265                 });
       
  1266 
       
  1267                 var message = callStr.replace(", [...", "[, ...") + " " +
       
  1268                     expectedCallCountInWords(this);
       
  1269 
       
  1270                 if (this.met()) {
       
  1271                     return "Expectation met: " + message;
       
  1272                 }
       
  1273 
       
  1274                 return "Expected " + message + " (" +
       
  1275                     callCountInWords(this.callCount) + ")";
       
  1276             },
       
  1277 
       
  1278             verify: function verify() {
       
  1279                 if (!this.met()) {
       
  1280                     sinon.expectation.fail(this.toString());
       
  1281                 }
       
  1282 
       
  1283                 return true;
       
  1284             },
       
  1285 
       
  1286             fail: function (message) {
       
  1287                 var exception = new Error(message);
       
  1288                 exception.name = "ExpectationError";
       
  1289 
       
  1290                 throw exception;
       
  1291             }
       
  1292         };
       
  1293     }());
       
  1294 
       
  1295     if (commonJSModule) {
       
  1296         module.exports = mock;
       
  1297     } else {
       
  1298         sinon.mock = mock;
       
  1299     }
       
  1300 }(typeof sinon == "object" && sinon || null));
       
  1301 
       
  1302 /**
       
  1303  * @depend ../sinon.js
       
  1304  * @depend stub.js
       
  1305  * @depend mock.js
       
  1306  */
       
  1307 /*jslint eqeqeq: false, onevar: false, forin: true*/
       
  1308 /*global module, require, sinon*/
       
  1309 /**
       
  1310  * Collections of stubs, spies and mocks.
       
  1311  *
       
  1312  * @author Christian Johansen (christian@cjohansen.no)
       
  1313  * @license BSD
       
  1314  *
       
  1315  * Copyright (c) 2010-2011 Christian Johansen
       
  1316  */
       
  1317 
       
  1318 (function (sinon) {
       
  1319     var commonJSModule = typeof module == "object" && typeof require == "function";
       
  1320     var push = [].push;
       
  1321 
       
  1322     if (!sinon && commonJSModule) {
       
  1323         sinon = require("../sinon");
       
  1324     }
       
  1325 
       
  1326     if (!sinon) {
       
  1327         return;
       
  1328     }
       
  1329 
       
  1330     function getFakes(fakeCollection) {
       
  1331         if (!fakeCollection.fakes) {
       
  1332             fakeCollection.fakes = [];
       
  1333         }
       
  1334 
       
  1335         return fakeCollection.fakes;
       
  1336     }
       
  1337 
       
  1338     function each(fakeCollection, method) {
       
  1339         var fakes = getFakes(fakeCollection);
       
  1340 
       
  1341         for (var i = 0, l = fakes.length; i < l; i += 1) {
       
  1342             if (typeof fakes[i][method] == "function") {
       
  1343                 fakes[i][method]();
       
  1344             }
       
  1345         }
       
  1346     }
       
  1347 
       
  1348     function compact(fakeCollection) {
       
  1349         var fakes = getFakes(fakeCollection);
       
  1350         var i = 0;
       
  1351         while (i < fakes.length) {
       
  1352           fakes.splice(i, 1);
       
  1353         }
       
  1354     }
       
  1355 
       
  1356     var collection = {
       
  1357         verify: function resolve() {
       
  1358             each(this, "verify");
       
  1359         },
       
  1360 
       
  1361         restore: function restore() {
       
  1362             each(this, "restore");
       
  1363             compact(this);
       
  1364         },
       
  1365 
       
  1366         verifyAndRestore: function verifyAndRestore() {
       
  1367             var exception;
       
  1368 
       
  1369             try {
       
  1370                 this.verify();
       
  1371             } catch (e) {
       
  1372                 exception = e;
       
  1373             }
       
  1374 
       
  1375             this.restore();
       
  1376 
       
  1377             if (exception) {
       
  1378                 throw exception;
       
  1379             }
       
  1380         },
       
  1381 
       
  1382         add: function add(fake) {
       
  1383             push.call(getFakes(this), fake);
       
  1384             return fake;
       
  1385         },
       
  1386 
       
  1387         spy: function spy() {
       
  1388             return this.add(sinon.spy.apply(sinon, arguments));
       
  1389         },
       
  1390 
       
  1391         stub: function stub(object, property, value) {
       
  1392             if (property) {
       
  1393                 var original = object[property];
       
  1394 
       
  1395                 if (typeof original != "function") {
       
  1396                     if (!object.hasOwnProperty(property)) {
       
  1397                         throw new TypeError("Cannot stub non-existent own property " + property);
       
  1398                     }
       
  1399 
       
  1400                     object[property] = value;
       
  1401 
       
  1402                     return this.add({
       
  1403                         restore: function () {
       
  1404                             object[property] = original;
       
  1405                         }
       
  1406                     });
       
  1407                 }
       
  1408             }
       
  1409 
       
  1410             return this.add(sinon.stub.apply(sinon, arguments));
       
  1411         },
       
  1412 
       
  1413         mock: function mock() {
       
  1414             return this.add(sinon.mock.apply(sinon, arguments));
       
  1415         },
       
  1416 
       
  1417         inject: function inject(obj) {
       
  1418             var col = this;
       
  1419 
       
  1420             obj.spy = function () {
       
  1421                 return col.spy.apply(col, arguments);
       
  1422             };
       
  1423 
       
  1424             obj.stub = function () {
       
  1425                 return col.stub.apply(col, arguments);
       
  1426             };
       
  1427 
       
  1428             obj.mock = function () {
       
  1429                 return col.mock.apply(col, arguments);
       
  1430             };
       
  1431 
       
  1432             return obj;
       
  1433         }
       
  1434     };
       
  1435 
       
  1436     if (commonJSModule) {
       
  1437         module.exports = collection;
       
  1438     } else {
       
  1439         sinon.collection = collection;
       
  1440     }
       
  1441 }(typeof sinon == "object" && sinon || null));
       
  1442 
       
  1443 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
       
  1444 /*global module, require, window*/
       
  1445 /**
       
  1446  * Fake timer API
       
  1447  * setTimeout
       
  1448  * setInterval
       
  1449  * clearTimeout
       
  1450  * clearInterval
       
  1451  * tick
       
  1452  * reset
       
  1453  * Date
       
  1454  *
       
  1455  * Inspired by jsUnitMockTimeOut from JsUnit
       
  1456  *
       
  1457  * @author Christian Johansen (christian@cjohansen.no)
       
  1458  * @license BSD
       
  1459  *
       
  1460  * Copyright (c) 2010-2011 Christian Johansen
       
  1461  */
       
  1462 
       
  1463 if (typeof sinon == "undefined") {
       
  1464     var sinon = {};
       
  1465 }
       
  1466 
       
  1467 sinon.clock = (function () {
       
  1468     var id = 0;
       
  1469 
       
  1470     function addTimer(args, recurring) {
       
  1471         if (args.length === 0) {
       
  1472             throw new Error("Function requires at least 1 parameter");
       
  1473         }
       
  1474 
       
  1475         var toId = id++;
       
  1476         var delay = args[1] || 0;
       
  1477 
       
  1478         if (!this.timeouts) {
       
  1479             this.timeouts = {};
       
  1480         }
       
  1481 
       
  1482         this.timeouts[toId] = {
       
  1483             id: toId,
       
  1484             func: args[0],
       
  1485             callAt: this.now + delay
       
  1486         };
       
  1487 
       
  1488         if (recurring === true) {
       
  1489             this.timeouts[toId].interval = delay;
       
  1490         }
       
  1491 
       
  1492         return toId;
       
  1493     }
       
  1494 
       
  1495     function parseTime(str) {
       
  1496         if (!str) {
       
  1497             return 0;
       
  1498         }
       
  1499 
       
  1500         var strings = str.split(":");
       
  1501         var l = strings.length, i = l;
       
  1502         var ms = 0, parsed;
       
  1503 
       
  1504         if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
       
  1505             throw new Error("tick only understands numbers and 'h:m:s'");
       
  1506         }
       
  1507 
       
  1508         while (i--) {
       
  1509             parsed = parseInt(strings[i], 10);
       
  1510 
       
  1511             if (parsed >= 60) {
       
  1512                 throw new Error("Invalid time " + str);
       
  1513             }
       
  1514 
       
  1515             ms += parsed * Math.pow(60, (l - i - 1));
       
  1516         }
       
  1517 
       
  1518         return ms * 1000;
       
  1519     }
       
  1520 
       
  1521     function createObject(object) {
       
  1522         var newObject;
       
  1523 
       
  1524         if (Object.create) {
       
  1525             newObject = Object.create(object);
       
  1526         } else {
       
  1527             var F = function () {};
       
  1528             F.prototype = object;
       
  1529             newObject = new F();
       
  1530         }
       
  1531 
       
  1532         newObject.Date.clock = newObject;
       
  1533         return newObject;
       
  1534     }
       
  1535 
       
  1536     return {
       
  1537         now: 0,
       
  1538 
       
  1539         create: function create(now) {
       
  1540             var clock = createObject(this);
       
  1541 
       
  1542             if (typeof now == "number") {
       
  1543                 this.now = now;
       
  1544             }
       
  1545 
       
  1546             return clock;
       
  1547         },
       
  1548 
       
  1549         setTimeout: function setTimeout(callback, timeout) {
       
  1550             return addTimer.call(this, arguments, false);
       
  1551         },
       
  1552 
       
  1553         clearTimeout: function clearTimeout(timerId) {
       
  1554             if (!this.timeouts) {
       
  1555                 this.timeouts = [];
       
  1556             }
       
  1557 
       
  1558             delete this.timeouts[timerId];
       
  1559         },
       
  1560 
       
  1561         setInterval: function setInterval(callback, timeout) {
       
  1562             return addTimer.call(this, arguments, true);
       
  1563         },
       
  1564 
       
  1565         clearInterval: function clearInterval(timerId) {
       
  1566             this.clearTimeout(timerId);
       
  1567         },
       
  1568 
       
  1569         tick: function tick(ms) {
       
  1570             ms = typeof ms == "number" ? ms : parseTime(ms);
       
  1571             var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
       
  1572             var timer = this.firstTimerInRange(tickFrom, tickTo);
       
  1573 
       
  1574             while (timer && tickFrom <= tickTo) {
       
  1575                 if (this.timeouts[timer.id]) {
       
  1576                     tickFrom = this.now = timer.callAt;
       
  1577                     this.callTimer(timer);
       
  1578                 }
       
  1579 
       
  1580                 timer = this.firstTimerInRange(previous, tickTo);
       
  1581                 previous = tickFrom;
       
  1582             }
       
  1583 
       
  1584             this.now = tickTo;
       
  1585         },
       
  1586 
       
  1587         firstTimerInRange: function (from, to) {
       
  1588             var timer, smallest, originalTimer;
       
  1589 
       
  1590             for (var id in this.timeouts) {
       
  1591                 if (this.timeouts.hasOwnProperty(id)) {
       
  1592                     if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
       
  1593                         continue;
       
  1594                     }
       
  1595 
       
  1596                     if (!smallest || this.timeouts[id].callAt < smallest) {
       
  1597                         originalTimer = this.timeouts[id];
       
  1598                         smallest = this.timeouts[id].callAt;
       
  1599                         
       
  1600                         timer = {
       
  1601                             func: this.timeouts[id].func,
       
  1602                             callAt: this.timeouts[id].callAt,
       
  1603                             interval: this.timeouts[id].interval,
       
  1604                             id: this.timeouts[id].id
       
  1605                         };
       
  1606                     }
       
  1607                 }
       
  1608             }
       
  1609             
       
  1610             return timer || null;
       
  1611         },
       
  1612 
       
  1613         callTimer: function (timer) {
       
  1614             try {
       
  1615                 if (typeof timer.func == "function") {
       
  1616                     timer.func.call(null);
       
  1617                 } else {
       
  1618                     eval(timer.func);
       
  1619                 }
       
  1620             } catch (e) {}
       
  1621 
       
  1622             if (!this.timeouts[timer.id]) {
       
  1623                 return;
       
  1624             }
       
  1625 
       
  1626             if (typeof timer.interval == "number") {
       
  1627                 this.timeouts[timer.id].callAt += timer.interval;
       
  1628             } else {
       
  1629                 delete this.timeouts[timer.id];
       
  1630             }
       
  1631         },
       
  1632 
       
  1633         reset: function reset() {
       
  1634             this.timeouts = {};
       
  1635         },
       
  1636 
       
  1637         Date: (function () {
       
  1638             var NativeDate = Date;
       
  1639 
       
  1640             function ClockDate(year, month, date, hour, minute, second, ms) {
       
  1641                 // Defensive and verbose to avoid potential harm in passing
       
  1642                 // explicit undefined when user does not pass argument
       
  1643                 switch (arguments.length) {
       
  1644                 case 0:
       
  1645                     return new NativeDate(ClockDate.clock.now);
       
  1646                 case 1:
       
  1647                     return new NativeDate(year);
       
  1648                 case 2:
       
  1649                     return new NativeDate(year, month);
       
  1650                 case 3:
       
  1651                     return new NativeDate(year, month, date);
       
  1652                 case 4:
       
  1653                     return new NativeDate(year, month, date, hour);
       
  1654                 case 5:
       
  1655                     return new NativeDate(year, month, date, hour, minute);
       
  1656                 case 6:
       
  1657                     return new NativeDate(year, month, date, hour, minute, second);
       
  1658                 default:
       
  1659                     return new NativeDate(year, month, date, hour, minute, second, ms);
       
  1660                 }
       
  1661             }
       
  1662 
       
  1663             if (NativeDate.now) {
       
  1664                 ClockDate.now = function now() {
       
  1665                     return ClockDate.clock.now;
       
  1666                 };
       
  1667             }
       
  1668 
       
  1669             if (NativeDate.toSource) {
       
  1670                 ClockDate.toSource = function toSource() {
       
  1671                     return NativeDate.toSource();
       
  1672                 };
       
  1673             }
       
  1674 
       
  1675             ClockDate.toString = function toString() {
       
  1676                 return NativeDate.toString();
       
  1677             };
       
  1678 
       
  1679             ClockDate.prototype = NativeDate.prototype;
       
  1680             ClockDate.parse = NativeDate.parse;
       
  1681             ClockDate.UTC = NativeDate.UTC;
       
  1682 
       
  1683             return ClockDate;
       
  1684         }())
       
  1685     };
       
  1686 }());
       
  1687 
       
  1688 sinon.timers = {
       
  1689     setTimeout: setTimeout,
       
  1690     clearTimeout: clearTimeout,
       
  1691     setInterval: setInterval,
       
  1692     clearInterval: clearInterval,
       
  1693     Date: Date
       
  1694 };
       
  1695 
       
  1696 sinon.useFakeTimers = (function (global) {
       
  1697     var methods = ["Date", "setTimeout", "setInterval", "clearTimeout", "clearInterval"];
       
  1698 
       
  1699     function restore() {
       
  1700         var method;
       
  1701 
       
  1702         for (var i = 0, l = this.methods.length; i < l; i++) {
       
  1703             method = this.methods[i];
       
  1704             global[method] = this["_" + method];
       
  1705         }
       
  1706     }
       
  1707 
       
  1708     function stubGlobal(method, clock) {
       
  1709         clock["_" + method] = global[method];
       
  1710 
       
  1711         global[method] = function () {
       
  1712             return clock[method].apply(clock, arguments);
       
  1713         };
       
  1714 
       
  1715         for (var prop in clock[method]) {
       
  1716             if (clock[method].hasOwnProperty(prop)) {
       
  1717                 global[method][prop] = clock[method][prop];
       
  1718             }
       
  1719         }
       
  1720 
       
  1721         global[method].clock = clock;
       
  1722     }
       
  1723 
       
  1724     return function useFakeTimers(now) {
       
  1725         var clock = sinon.clock.create(now);
       
  1726         clock.restore = restore;
       
  1727         clock.methods = Array.prototype.slice.call(arguments,
       
  1728                                                    typeof now == "number" ? 1 : 0);
       
  1729 
       
  1730         if (clock.methods.length === 0) {
       
  1731             clock.methods = methods;
       
  1732         }
       
  1733 
       
  1734         for (var i = 0, l = clock.methods.length; i < l; i++) {
       
  1735             stubGlobal(clock.methods[i], clock);
       
  1736         }
       
  1737 
       
  1738         return clock;
       
  1739     };
       
  1740 }(typeof global != "undefined" ? global : this));
       
  1741 
       
  1742 if (typeof module == "object" && typeof require == "function") {
       
  1743     module.exports = sinon;
       
  1744 }
       
  1745 
       
  1746 /*jslint eqeqeq: false, onevar: false*/
       
  1747 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
       
  1748 /**
       
  1749  * Minimal Event interface implementation
       
  1750  *
       
  1751  * Original implementation by Sven Fuchs: https://gist.github.com/995028
       
  1752  * Modifications and tests by Christian Johansen.
       
  1753  *
       
  1754  * @author Sven Fuchs (svenfuchs@artweb-design.de)
       
  1755  * @author Christian Johansen (christian@cjohansen.no)
       
  1756  * @license BSD
       
  1757  *
       
  1758  * Copyright (c) 2011 Sven Fuchs, Christian Johansen
       
  1759  */
       
  1760 
       
  1761 if (typeof sinon == "undefined") {
       
  1762     this.sinon = {};
       
  1763 }
       
  1764 
       
  1765 (function () {
       
  1766     var push = [].push;
       
  1767 
       
  1768     sinon.Event = function Event(type, bubbles, cancelable) {
       
  1769         this.initEvent(type, bubbles, cancelable);
       
  1770     };
       
  1771 
       
  1772     sinon.Event.prototype = {
       
  1773         initEvent: function(type, bubbles, cancelable) {
       
  1774             this.type = type;
       
  1775             this.bubbles = bubbles;
       
  1776             this.cancelable = cancelable;
       
  1777         },
       
  1778 
       
  1779         stopPropagation: function () {},
       
  1780 
       
  1781         preventDefault: function () {
       
  1782             this.defaultPrevented = true;
       
  1783         }
       
  1784     };
       
  1785 
       
  1786     sinon.EventTarget = {
       
  1787         addEventListener: function addEventListener(event, listener, useCapture) {
       
  1788             this.eventListeners = this.eventListeners || {};
       
  1789             this.eventListeners[event] = this.eventListeners[event] || [];
       
  1790             push.call(this.eventListeners[event], listener);
       
  1791         },
       
  1792 
       
  1793         removeEventListener: function removeEventListener(event, listener, useCapture) {
       
  1794             var listeners = this.eventListeners && this.eventListeners[event] || [];
       
  1795 
       
  1796             for (var i = 0, l = listeners.length; i < l; ++i) {
       
  1797                 if (listeners[i] == listener) {
       
  1798                     return listeners.splice(i, 1);
       
  1799                 }
       
  1800             }
       
  1801         },
       
  1802 
       
  1803         dispatchEvent: function dispatchEvent(event) {
       
  1804             var type = event.type;
       
  1805             var listeners = this.eventListeners && this.eventListeners[type] || [];
       
  1806 
       
  1807             for (var i = 0; i < listeners.length; i++) {
       
  1808                 if (typeof listeners[i] == "function") {
       
  1809                     listeners[i].call(this, event);
       
  1810                 } else {
       
  1811                     listeners[i].handleEvent(event);
       
  1812                 }
       
  1813             }
       
  1814 
       
  1815             return !!event.defaultPrevented;
       
  1816         }
       
  1817     };
       
  1818 }());
       
  1819 
       
  1820 /**
       
  1821  * @depend event.js
       
  1822  */
       
  1823 /*jslint eqeqeq: false, onevar: false*/
       
  1824 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
       
  1825 /**
       
  1826  * Fake XMLHttpRequest object
       
  1827  *
       
  1828  * @author Christian Johansen (christian@cjohansen.no)
       
  1829  * @license BSD
       
  1830  *
       
  1831  * Copyright (c) 2010-2011 Christian Johansen
       
  1832  */
       
  1833 
       
  1834 if (typeof sinon == "undefined") {
       
  1835     this.sinon = {};
       
  1836 }
       
  1837 
       
  1838 sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
       
  1839 
       
  1840 sinon.FakeXMLHttpRequest = (function () {
       
  1841     /*jsl:ignore*/
       
  1842     var unsafeHeaders = {
       
  1843         "Accept-Charset": true,
       
  1844         "Accept-Encoding": true,
       
  1845         "Connection": true,
       
  1846         "Content-Length": true,
       
  1847         "Cookie": true,
       
  1848         "Cookie2": true,
       
  1849         "Content-Transfer-Encoding": true,
       
  1850         "Date": true,
       
  1851         "Expect": true,
       
  1852         "Host": true,
       
  1853         "Keep-Alive": true,
       
  1854         "Referer": true,
       
  1855         "TE": true,
       
  1856         "Trailer": true,
       
  1857         "Transfer-Encoding": true,
       
  1858         "Upgrade": true,
       
  1859         "User-Agent": true,
       
  1860         "Via": true
       
  1861     };
       
  1862     /*jsl:end*/
       
  1863 
       
  1864     function FakeXMLHttpRequest() {
       
  1865         this.readyState = FakeXMLHttpRequest.UNSENT;
       
  1866         this.requestHeaders = {};
       
  1867         this.requestBody = null;
       
  1868         this.status = 0;
       
  1869         this.statusText = "";
       
  1870 
       
  1871         if (typeof FakeXMLHttpRequest.onCreate == "function") {
       
  1872             FakeXMLHttpRequest.onCreate(this);
       
  1873         }
       
  1874     }
       
  1875 
       
  1876     function verifyState(xhr) {
       
  1877         if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
       
  1878             throw new Error("INVALID_STATE_ERR");
       
  1879         }
       
  1880 
       
  1881         if (xhr.sendFlag) {
       
  1882             throw new Error("INVALID_STATE_ERR");
       
  1883         }
       
  1884     }
       
  1885 
       
  1886     sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
       
  1887         async: true,
       
  1888 
       
  1889         open: function open(method, url, async, username, password) {
       
  1890             this.method = method;
       
  1891             this.url = url;
       
  1892             this.async = typeof async == "boolean" ? async : true;
       
  1893             this.username = username;
       
  1894             this.password = password;
       
  1895             this.responseText = null;
       
  1896             this.responseXML = null;
       
  1897             this.requestHeaders = {};
       
  1898             this.sendFlag = false;
       
  1899             this.readyStateChange(FakeXMLHttpRequest.OPENED);
       
  1900         },
       
  1901 
       
  1902         readyStateChange: function readyStateChange(state) {
       
  1903             this.readyState = state;
       
  1904 
       
  1905             if (typeof this.onreadystatechange == "function") {
       
  1906                 this.onreadystatechange();
       
  1907             }
       
  1908 
       
  1909             this.dispatchEvent(new sinon.Event("readystatechange"));
       
  1910         },
       
  1911 
       
  1912         setRequestHeader: function setRequestHeader(header, value) {
       
  1913             verifyState(this);
       
  1914 
       
  1915             if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
       
  1916                 throw new Error("Refused to set unsafe header \"" + header + "\"");
       
  1917             }
       
  1918 
       
  1919             if (this.requestHeaders[header]) {
       
  1920                 this.requestHeaders[header] += "," + value; 
       
  1921             } else {
       
  1922                 this.requestHeaders[header] = value;
       
  1923             }
       
  1924         },
       
  1925 
       
  1926         // Helps testing
       
  1927         setResponseHeaders: function setResponseHeaders(headers) {
       
  1928             this.responseHeaders = {};
       
  1929 
       
  1930             for (var header in headers) {
       
  1931                 if (headers.hasOwnProperty(header)) {
       
  1932                     this.responseHeaders[header] = headers[header];
       
  1933                 }
       
  1934             }
       
  1935 
       
  1936             if (this.async) {
       
  1937                 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
       
  1938             }
       
  1939         },
       
  1940 
       
  1941         // Currently treats ALL data as a DOMString (i.e. no Document)
       
  1942         send: function send(data) {
       
  1943             verifyState(this);
       
  1944 
       
  1945             if (!/^(get|head)$/i.test(this.method)) {
       
  1946                 if (this.requestHeaders["Content-Type"]) {
       
  1947                     var value = this.requestHeaders["Content-Type"].split(";");
       
  1948                     this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
       
  1949                 } else {
       
  1950                     this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
       
  1951                 }
       
  1952 
       
  1953                 this.requestBody = data;
       
  1954             }
       
  1955 
       
  1956             this.errorFlag = false;
       
  1957             this.sendFlag = this.async;
       
  1958             this.readyStateChange(FakeXMLHttpRequest.OPENED);
       
  1959 
       
  1960             if (typeof this.onSend == "function") {
       
  1961                 this.onSend(this);
       
  1962             }
       
  1963         },
       
  1964 
       
  1965         abort: function abort() {
       
  1966             this.aborted = true;
       
  1967             this.responseText = null;
       
  1968             this.errorFlag = true;
       
  1969             this.requestHeaders = {};
       
  1970 
       
  1971             if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
       
  1972                 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
       
  1973                 this.sendFlag = false;
       
  1974             }
       
  1975 
       
  1976             this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
       
  1977         },
       
  1978 
       
  1979         getResponseHeader: function getResponseHeader(header) {
       
  1980             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
       
  1981                 return null;
       
  1982             }
       
  1983 
       
  1984             if (/^Set-Cookie2?$/i.test(header)) {
       
  1985                 return null;
       
  1986             }
       
  1987 
       
  1988             header = header.toLowerCase();
       
  1989 
       
  1990             for (var h in this.responseHeaders) {
       
  1991                 if (h.toLowerCase() == header) {
       
  1992                     return this.responseHeaders[h];
       
  1993                 }
       
  1994             }
       
  1995 
       
  1996             return null;
       
  1997         },
       
  1998 
       
  1999         getAllResponseHeaders: function getAllResponseHeaders() {
       
  2000             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
       
  2001                 return "";
       
  2002             }
       
  2003 
       
  2004             var headers = "";
       
  2005 
       
  2006             for (var header in this.responseHeaders) {
       
  2007                 if (this.responseHeaders.hasOwnProperty(header) &&
       
  2008                     !/^Set-Cookie2?$/i.test(header)) {
       
  2009                     headers += header + ": " + this.responseHeaders[header] + "\r\n";
       
  2010                 }
       
  2011             }
       
  2012 
       
  2013             return headers;
       
  2014         },
       
  2015 
       
  2016         setResponseBody: function setResponseBody(body) {
       
  2017             if (this.readyState == FakeXMLHttpRequest.DONE) {
       
  2018                 throw new Error("Request done");
       
  2019             }
       
  2020 
       
  2021             if (this.async && this.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
       
  2022                 throw new Error("No headers received");
       
  2023             }
       
  2024 
       
  2025             var chunkSize = this.chunkSize || 10;
       
  2026             var index = 0;
       
  2027             this.responseText = "";
       
  2028 
       
  2029             do {
       
  2030                 if (this.async) {
       
  2031                     this.readyStateChange(FakeXMLHttpRequest.LOADING);
       
  2032                 }
       
  2033 
       
  2034                 this.responseText += body.substring(index, index + chunkSize);
       
  2035                 index += chunkSize;
       
  2036             } while (index < body.length);
       
  2037 
       
  2038             var type = this.getResponseHeader("Content-Type");
       
  2039 
       
  2040             if (this.responseText &&
       
  2041                 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
       
  2042                 try {
       
  2043                     this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
       
  2044                 } catch (e) {}
       
  2045             }
       
  2046 
       
  2047             if (this.async) {
       
  2048                 this.readyStateChange(FakeXMLHttpRequest.DONE);
       
  2049             } else {
       
  2050                 this.readyState = FakeXMLHttpRequest.DONE;
       
  2051             }
       
  2052         },
       
  2053 
       
  2054         respond: function respond(status, headers, body) {
       
  2055             this.setResponseHeaders(headers || {});
       
  2056             this.status = typeof status == "number" ? status : 200;
       
  2057             this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
       
  2058             this.setResponseBody(body || "");
       
  2059         }
       
  2060     });
       
  2061 
       
  2062     sinon.extend(FakeXMLHttpRequest, {
       
  2063         UNSENT: 0,
       
  2064         OPENED: 1,
       
  2065         HEADERS_RECEIVED: 2,
       
  2066         LOADING: 3,
       
  2067         DONE: 4
       
  2068     });
       
  2069 
       
  2070     // Borrowed from JSpec
       
  2071     FakeXMLHttpRequest.parseXML = function parseXML(text) {
       
  2072         var xmlDoc;
       
  2073 
       
  2074         if (typeof DOMParser != "undefined") {
       
  2075             var parser = new DOMParser();
       
  2076             xmlDoc = parser.parseFromString(text, "text/xml");
       
  2077         } else {
       
  2078             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
       
  2079             xmlDoc.async = "false";
       
  2080             xmlDoc.loadXML(text);
       
  2081         }
       
  2082 
       
  2083         return xmlDoc;
       
  2084     };
       
  2085 
       
  2086     FakeXMLHttpRequest.statusCodes = {
       
  2087         100: "Continue",
       
  2088         101: "Switching Protocols",
       
  2089         200: "OK",
       
  2090         201: "Created",
       
  2091         202: "Accepted",
       
  2092         203: "Non-Authoritative Information",
       
  2093         204: "No Content",
       
  2094         205: "Reset Content",
       
  2095         206: "Partial Content",
       
  2096         300: "Multiple Choice",
       
  2097         301: "Moved Permanently",
       
  2098         302: "Found",
       
  2099         303: "See Other",
       
  2100         304: "Not Modified",
       
  2101         305: "Use Proxy",
       
  2102         307: "Temporary Redirect",
       
  2103         400: "Bad Request",
       
  2104         401: "Unauthorized",
       
  2105         402: "Payment Required",
       
  2106         403: "Forbidden",
       
  2107         404: "Not Found",
       
  2108         405: "Method Not Allowed",
       
  2109         406: "Not Acceptable",
       
  2110         407: "Proxy Authentication Required",
       
  2111         408: "Request Timeout",
       
  2112         409: "Conflict",
       
  2113         410: "Gone",
       
  2114         411: "Length Required",
       
  2115         412: "Precondition Failed",
       
  2116         413: "Request Entity Too Large",
       
  2117         414: "Request-URI Too Long",
       
  2118         415: "Unsupported Media Type",
       
  2119         416: "Requested Range Not Satisfiable",
       
  2120         417: "Expectation Failed",
       
  2121         422: "Unprocessable Entity",
       
  2122         500: "Internal Server Error",
       
  2123         501: "Not Implemented",
       
  2124         502: "Bad Gateway",
       
  2125         503: "Service Unavailable",
       
  2126         504: "Gateway Timeout",
       
  2127         505: "HTTP Version Not Supported"
       
  2128     };
       
  2129 
       
  2130     return FakeXMLHttpRequest;
       
  2131 }());
       
  2132 
       
  2133 (function (global) {
       
  2134     var GlobalXMLHttpRequest = global.XMLHttpRequest;
       
  2135     var GlobalActiveXObject = global.ActiveXObject;
       
  2136     var supportsActiveX = typeof ActiveXObject != "undefined";
       
  2137     var supportsXHR = typeof XMLHttpRequest != "undefined";
       
  2138 
       
  2139     sinon.useFakeXMLHttpRequest = function () {
       
  2140         sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
       
  2141             if (supportsXHR) {
       
  2142                 global.XMLHttpRequest = GlobalXMLHttpRequest;
       
  2143             }
       
  2144 
       
  2145             if (supportsActiveX) {
       
  2146                 global.ActiveXObject = GlobalActiveXObject;
       
  2147             }
       
  2148 
       
  2149             delete sinon.FakeXMLHttpRequest.restore;
       
  2150 
       
  2151             if (keepOnCreate !== true) {
       
  2152                 delete sinon.FakeXMLHttpRequest.onCreate;
       
  2153             }
       
  2154         };
       
  2155 
       
  2156         if (supportsXHR) {
       
  2157             global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
       
  2158         }
       
  2159 
       
  2160         if (supportsActiveX) {
       
  2161             global.ActiveXObject = function ActiveXObject(objId) {
       
  2162                 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
       
  2163                     return new sinon.FakeXMLHttpRequest();
       
  2164                 }
       
  2165 
       
  2166                 return new GlobalActiveXObject(objId);
       
  2167             };
       
  2168         }
       
  2169 
       
  2170         return sinon.FakeXMLHttpRequest;
       
  2171     };
       
  2172 }(this));
       
  2173 
       
  2174 if (typeof module == "object" && typeof require == "function") {
       
  2175     module.exports = sinon;
       
  2176 }
       
  2177 
       
  2178 /**
       
  2179  * @depend fake_xml_http_request.js
       
  2180  */
       
  2181 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
       
  2182 /*global module, require, window*/
       
  2183 /**
       
  2184  * The Sinon "server" mimics a web server that receives requests from
       
  2185  * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
       
  2186  * both synchronously and asynchronously. To respond synchronuously, canned
       
  2187  * answers have to be provided upfront.
       
  2188  *
       
  2189  * @author Christian Johansen (christian@cjohansen.no)
       
  2190  * @license BSD
       
  2191  *
       
  2192  * Copyright (c) 2010-2011 Christian Johansen
       
  2193  */
       
  2194 
       
  2195 if (typeof sinon == "undefined") {
       
  2196     var sinon = {};
       
  2197 }
       
  2198 
       
  2199 sinon.fakeServer = (function () {
       
  2200     var push = [].push;
       
  2201     function F() {}
       
  2202 
       
  2203     function create(proto) {
       
  2204         F.prototype = proto;
       
  2205         return new F();
       
  2206     }
       
  2207 
       
  2208     function responseArray(handler) {
       
  2209         var response = handler;
       
  2210 
       
  2211         if (Object.prototype.toString.call(handler) != "[object Array]") {
       
  2212             response = [200, {}, handler];
       
  2213         }
       
  2214 
       
  2215         if (typeof response[2] != "string") {
       
  2216             throw new TypeError("Fake server response body should be string, but was " +
       
  2217                                 typeof response[2]);
       
  2218         }
       
  2219 
       
  2220         return response;
       
  2221     }
       
  2222 
       
  2223     var wloc = window.location;
       
  2224     var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
       
  2225 
       
  2226     function matchOne(response, reqMethod, reqUrl) {
       
  2227         var rmeth = response.method;
       
  2228         var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
       
  2229         var url = response.url;
       
  2230         var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
       
  2231 
       
  2232         return matchMethod && matchUrl;
       
  2233     }
       
  2234 
       
  2235     function match(response, request) {
       
  2236         var requestMethod = this.getHTTPMethod(request);
       
  2237         var requestUrl = request.url;
       
  2238 
       
  2239         if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
       
  2240             requestUrl = requestUrl.replace(rCurrLoc, "");
       
  2241         }
       
  2242 
       
  2243         if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
       
  2244             if (typeof response.response == "function") {
       
  2245                 var args = [request].concat(requestUrl.match(response.url).slice(1));
       
  2246                 return response.response.apply(response, args);
       
  2247             }
       
  2248 
       
  2249             return true;
       
  2250         }
       
  2251 
       
  2252         return false;
       
  2253     }
       
  2254 
       
  2255     return {
       
  2256         create: function () {
       
  2257             var server = create(this);
       
  2258             this.xhr = sinon.useFakeXMLHttpRequest();
       
  2259             server.requests = [];
       
  2260 
       
  2261             this.xhr.onCreate = function (xhrObj) {
       
  2262                 server.addRequest(xhrObj);
       
  2263             };
       
  2264 
       
  2265             return server;
       
  2266         },
       
  2267 
       
  2268         addRequest: function addRequest(xhrObj) {
       
  2269             var server = this;
       
  2270             push.call(this.requests, xhrObj);
       
  2271 
       
  2272             xhrObj.onSend = function () {
       
  2273                 server.handleRequest(this);
       
  2274             };
       
  2275 
       
  2276             if (this.autoRespond && !this.responding) {
       
  2277                 setTimeout(function () {
       
  2278                     server.responding = false;
       
  2279                     server.respond();
       
  2280                 }, this.autoRespondAfter || 10);
       
  2281 
       
  2282                 this.responding = true;
       
  2283             }
       
  2284         },
       
  2285 
       
  2286         getHTTPMethod: function getHTTPMethod(request) {
       
  2287             if (this.fakeHTTPMethods && /post/i.test(request.method)) {
       
  2288                 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
       
  2289                 return !!matches ? matches[1] : request.method;
       
  2290             }
       
  2291 
       
  2292             return request.method;
       
  2293         },
       
  2294 
       
  2295         handleRequest: function handleRequest(xhr) {
       
  2296             if (xhr.async) {
       
  2297                 if (!this.queue) {
       
  2298                     this.queue = [];
       
  2299                 }
       
  2300 
       
  2301                 push.call(this.queue, xhr);
       
  2302             } else {
       
  2303                 this.processRequest(xhr);
       
  2304             }
       
  2305         },
       
  2306 
       
  2307         respondWith: function respondWith(method, url, body) {
       
  2308             if (arguments.length == 1) {
       
  2309                 this.response = responseArray(method);
       
  2310             } else {
       
  2311                 if (!this.responses) {
       
  2312                     this.responses = [];
       
  2313                 }
       
  2314 
       
  2315                 if (arguments.length == 2) {
       
  2316                     body = url;
       
  2317                     url = method;
       
  2318                     method = null;
       
  2319                 }
       
  2320 
       
  2321                 push.call(this.responses, {
       
  2322                     method: method,
       
  2323                     url: url,
       
  2324                     response: typeof body == "function" ? body : responseArray(body)
       
  2325                 });
       
  2326             }
       
  2327         },
       
  2328 
       
  2329         respond: function respond() {
       
  2330             var queue = this.queue || [];
       
  2331             var request;
       
  2332 
       
  2333             while(request = queue.shift()) {
       
  2334                 this.processRequest(request);
       
  2335             }
       
  2336         },
       
  2337 
       
  2338         processRequest: function processRequest(request) {
       
  2339             try {
       
  2340                 if (request.aborted) {
       
  2341                     return;
       
  2342                 }
       
  2343 
       
  2344                 var response = this.response || [404, {}, ""];
       
  2345 
       
  2346                 if (this.responses) {
       
  2347                     for (var i = 0, l = this.responses.length; i < l; i++) {
       
  2348                         if (match.call(this, this.responses[i], request)) {
       
  2349                             response = this.responses[i].response;
       
  2350                             break;
       
  2351                         }
       
  2352                     }
       
  2353                 }
       
  2354 
       
  2355                 if (request.readyState != 4) {
       
  2356                     request.respond(response[0], response[1], response[2]);
       
  2357                 }
       
  2358             } catch (e) {}
       
  2359         },
       
  2360 
       
  2361         restore: function restore() {
       
  2362             return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
       
  2363         }
       
  2364     };
       
  2365 }());
       
  2366 
       
  2367 if (typeof module == "object" && typeof require == "function") {
       
  2368     module.exports = sinon;
       
  2369 }
       
  2370 
       
  2371 /**
       
  2372  * @depend fake_server.js
       
  2373  * @depend fake_timers.js
       
  2374  */
       
  2375 /*jslint browser: true, eqeqeq: false, onevar: false*/
       
  2376 /*global sinon*/
       
  2377 /**
       
  2378  * Add-on for sinon.fakeServer that automatically handles a fake timer along with
       
  2379  * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
       
  2380  * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
       
  2381  * it polls the object for completion with setInterval. Dispite the direct
       
  2382  * motivation, there is nothing jQuery-specific in this file, so it can be used
       
  2383  * in any environment where the ajax implementation depends on setInterval or
       
  2384  * setTimeout.
       
  2385  *
       
  2386  * @author Christian Johansen (christian@cjohansen.no)
       
  2387  * @license BSD
       
  2388  *
       
  2389  * Copyright (c) 2010-2011 Christian Johansen
       
  2390  */
       
  2391 
       
  2392 (function () {
       
  2393     function Server() {}
       
  2394     Server.prototype = sinon.fakeServer;
       
  2395 
       
  2396     sinon.fakeServerWithClock = new Server();
       
  2397 
       
  2398     sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
       
  2399         if (xhr.async) {
       
  2400             if (typeof setTimeout.clock == "object") {
       
  2401                 this.clock = setTimeout.clock;
       
  2402             } else {
       
  2403                 this.clock = sinon.useFakeTimers();
       
  2404                 this.resetClock = true;
       
  2405             }
       
  2406 
       
  2407             if (!this.longestTimeout) {
       
  2408                 var clockSetTimeout = this.clock.setTimeout;
       
  2409                 var clockSetInterval = this.clock.setInterval;
       
  2410                 var server = this;
       
  2411 
       
  2412                 this.clock.setTimeout = function (fn, timeout) {
       
  2413                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
       
  2414 
       
  2415                     return clockSetTimeout.apply(this, arguments);
       
  2416                 };
       
  2417 
       
  2418                 this.clock.setInterval = function (fn, timeout) {
       
  2419                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
       
  2420 
       
  2421                     return clockSetInterval.apply(this, arguments);
       
  2422                 };
       
  2423             }
       
  2424         }
       
  2425 
       
  2426         return sinon.fakeServer.addRequest.call(this, xhr);
       
  2427     };
       
  2428 
       
  2429     sinon.fakeServerWithClock.respond = function respond() {
       
  2430         var returnVal = sinon.fakeServer.respond.apply(this, arguments);
       
  2431 
       
  2432         if (this.clock) {
       
  2433             this.clock.tick(this.longestTimeout || 0);
       
  2434             this.longestTimeout = 0;
       
  2435 
       
  2436             if (this.resetClock) {
       
  2437                 this.clock.restore();
       
  2438                 this.resetClock = false;
       
  2439             }
       
  2440         }
       
  2441 
       
  2442         return returnVal;
       
  2443     };
       
  2444 
       
  2445     sinon.fakeServerWithClock.restore = function restore() {
       
  2446         if (this.clock) {
       
  2447             this.clock.restore();
       
  2448         }
       
  2449 
       
  2450         return sinon.fakeServer.restore.apply(this, arguments);
       
  2451     };
       
  2452 }());
       
  2453 
       
  2454 /**
       
  2455  * @depend ../sinon.js
       
  2456  * @depend collection.js
       
  2457  * @depend util/fake_timers.js
       
  2458  * @depend util/fake_server_with_clock.js
       
  2459  */
       
  2460 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
       
  2461 /*global require, module*/
       
  2462 /**
       
  2463  * Manages fake collections as well as fake utilities such as Sinon's
       
  2464  * timers and fake XHR implementation in one convenient object.
       
  2465  *
       
  2466  * @author Christian Johansen (christian@cjohansen.no)
       
  2467  * @license BSD
       
  2468  *
       
  2469  * Copyright (c) 2010-2011 Christian Johansen
       
  2470  */
       
  2471 
       
  2472 if (typeof module == "object" && typeof require == "function") {
       
  2473     var sinon = require("../sinon");
       
  2474     sinon.extend(sinon, require("./util/fake_timers"));
       
  2475 }
       
  2476 
       
  2477 (function () {
       
  2478     var push = [].push;
       
  2479 
       
  2480     function exposeValue(sandbox, config, key, value) {
       
  2481         if (!value) {
       
  2482             return;
       
  2483         }
       
  2484 
       
  2485         if (config.injectInto) {
       
  2486             config.injectInto[key] = value;
       
  2487         } else {
       
  2488             push.call(sandbox.args, value);
       
  2489         }
       
  2490     }
       
  2491 
       
  2492     function prepareSandboxFromConfig(config) {
       
  2493         var sandbox = sinon.create(sinon.sandbox);
       
  2494 
       
  2495         if (config.useFakeServer) {
       
  2496             if (typeof config.useFakeServer == "object") {
       
  2497                 sandbox.serverPrototype = config.useFakeServer;
       
  2498             }
       
  2499 
       
  2500             sandbox.useFakeServer();
       
  2501         }
       
  2502 
       
  2503         if (config.useFakeTimers) {
       
  2504             if (typeof config.useFakeTimers == "object") {
       
  2505                 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
       
  2506             } else {
       
  2507                 sandbox.useFakeTimers();
       
  2508             }
       
  2509         }
       
  2510 
       
  2511         return sandbox;
       
  2512     }
       
  2513 
       
  2514     sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
       
  2515         useFakeTimers: function useFakeTimers() {
       
  2516             this.clock = sinon.useFakeTimers.apply(sinon, arguments);
       
  2517 
       
  2518             return this.add(this.clock);
       
  2519         },
       
  2520 
       
  2521         serverPrototype: sinon.fakeServer,
       
  2522 
       
  2523         useFakeServer: function useFakeServer() {
       
  2524             var proto = this.serverPrototype || sinon.fakeServer;
       
  2525 
       
  2526             if (!proto || !proto.create) {
       
  2527                 return null;
       
  2528             }
       
  2529 
       
  2530             this.server = proto.create();
       
  2531             return this.add(this.server);
       
  2532         },
       
  2533 
       
  2534         inject: function (obj) {
       
  2535             sinon.collection.inject.call(this, obj);
       
  2536 
       
  2537             if (this.clock) {
       
  2538                 obj.clock = this.clock;
       
  2539             }
       
  2540 
       
  2541             if (this.server) {
       
  2542                 obj.server = this.server;
       
  2543                 obj.requests = this.server.requests;
       
  2544             }
       
  2545 
       
  2546             return obj;
       
  2547         },
       
  2548 
       
  2549         create: function (config) {
       
  2550             if (!config) {
       
  2551                 return sinon.create(sinon.sandbox);
       
  2552             }
       
  2553 
       
  2554             var sandbox = prepareSandboxFromConfig(config);
       
  2555             sandbox.args = sandbox.args || [];
       
  2556             var prop, value, exposed = sandbox.inject({});
       
  2557 
       
  2558             if (config.properties) {
       
  2559                 for (var i = 0, l = config.properties.length; i < l; i++) {
       
  2560                     prop = config.properties[i];
       
  2561                     value = exposed[prop] || prop == "sandbox" && sandbox;
       
  2562                     exposeValue(sandbox, config, prop, value);
       
  2563                 }
       
  2564             } else {
       
  2565                 exposeValue(sandbox, config, "sandbox", value);
       
  2566             }
       
  2567 
       
  2568             return sandbox;
       
  2569         }
       
  2570     });
       
  2571 
       
  2572     sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
       
  2573 
       
  2574     if (typeof module != "undefined") {
       
  2575         module.exports = sinon.sandbox;
       
  2576     }
       
  2577 }());
       
  2578 
       
  2579 /**
       
  2580  * @depend ../sinon.js
       
  2581  * @depend stub.js
       
  2582  * @depend mock.js
       
  2583  * @depend sandbox.js
       
  2584  */
       
  2585 /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
       
  2586 /*global module, require, sinon*/
       
  2587 /**
       
  2588  * Test function, sandboxes fakes
       
  2589  *
       
  2590  * @author Christian Johansen (christian@cjohansen.no)
       
  2591  * @license BSD
       
  2592  *
       
  2593  * Copyright (c) 2010-2011 Christian Johansen
       
  2594  */
       
  2595 
       
  2596 (function (sinon) {
       
  2597     var commonJSModule = typeof module == "object" && typeof require == "function";
       
  2598 
       
  2599     if (!sinon && commonJSModule) {
       
  2600         sinon = require("../sinon");
       
  2601     }
       
  2602 
       
  2603     if (!sinon) {
       
  2604         return;
       
  2605     }
       
  2606 
       
  2607     function test(callback) {
       
  2608         var type = typeof callback;
       
  2609 
       
  2610         if (type != "function") {
       
  2611             throw new TypeError("sinon.test needs to wrap a test function, got " + type);
       
  2612         }
       
  2613 
       
  2614         return function () {
       
  2615             var config = sinon.getConfig(sinon.config);
       
  2616             config.injectInto = config.injectIntoThis && this || config.injectInto;
       
  2617             var sandbox = sinon.sandbox.create(config);
       
  2618             var exception, result;
       
  2619             var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
       
  2620 
       
  2621             try {
       
  2622                 result = callback.apply(this, args);
       
  2623             } catch (e) {
       
  2624                 exception = e;
       
  2625             }
       
  2626 
       
  2627             sandbox.verifyAndRestore();
       
  2628 
       
  2629             if (exception) {
       
  2630                 throw exception;
       
  2631             }
       
  2632 
       
  2633             return result;
       
  2634         };
       
  2635     }
       
  2636 
       
  2637     test.config = {
       
  2638         injectIntoThis: true,
       
  2639         injectInto: null,
       
  2640         properties: ["spy", "stub", "mock", "clock", "server", "requests"],
       
  2641         useFakeTimers: true,
       
  2642         useFakeServer: true
       
  2643     };
       
  2644 
       
  2645     if (commonJSModule) {
       
  2646         module.exports = test;
       
  2647     } else {
       
  2648         sinon.test = test;
       
  2649     }
       
  2650 }(typeof sinon == "object" && sinon || null));
       
  2651 
       
  2652 /**
       
  2653  * @depend ../sinon.js
       
  2654  * @depend test.js
       
  2655  */
       
  2656 /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
       
  2657 /*global module, require, sinon*/
       
  2658 /**
       
  2659  * Test case, sandboxes all test functions
       
  2660  *
       
  2661  * @author Christian Johansen (christian@cjohansen.no)
       
  2662  * @license BSD
       
  2663  *
       
  2664  * Copyright (c) 2010-2011 Christian Johansen
       
  2665  */
       
  2666 
       
  2667 (function (sinon) {
       
  2668     var commonJSModule = typeof module == "object" && typeof require == "function";
       
  2669 
       
  2670     if (!sinon && commonJSModule) {
       
  2671         sinon = require("../sinon");
       
  2672     }
       
  2673 
       
  2674     if (!sinon || !Object.prototype.hasOwnProperty) {
       
  2675         return;
       
  2676     }
       
  2677 
       
  2678     function createTest(property, setUp, tearDown) {
       
  2679         return function () {
       
  2680             if (setUp) {
       
  2681                 setUp.apply(this, arguments);
       
  2682             }
       
  2683 
       
  2684             var exception, result;
       
  2685 
       
  2686             try {
       
  2687                 result = property.apply(this, arguments);
       
  2688             } catch (e) {
       
  2689                 exception = e;
       
  2690             }
       
  2691 
       
  2692             if (tearDown) {
       
  2693                 tearDown.apply(this, arguments);
       
  2694             }
       
  2695 
       
  2696             if (exception) {
       
  2697                 throw exception;
       
  2698             }
       
  2699 
       
  2700             return result;
       
  2701         };
       
  2702     }
       
  2703 
       
  2704     function testCase(tests, prefix) {
       
  2705         /*jsl:ignore*/
       
  2706         if (!tests || typeof tests != "object") {
       
  2707             throw new TypeError("sinon.testCase needs an object with test functions");
       
  2708         }
       
  2709         /*jsl:end*/
       
  2710 
       
  2711         prefix = prefix || "test";
       
  2712         var rPrefix = new RegExp("^" + prefix);
       
  2713         var methods = {}, testName, property, method;
       
  2714         var setUp = tests.setUp;
       
  2715         var tearDown = tests.tearDown;
       
  2716 
       
  2717         for (testName in tests) {
       
  2718             if (tests.hasOwnProperty(testName)) {
       
  2719                 property = tests[testName];
       
  2720 
       
  2721                 if (/^(setUp|tearDown)$/.test(testName)) {
       
  2722                     continue;
       
  2723                 }
       
  2724 
       
  2725                 if (typeof property == "function" && rPrefix.test(testName)) {
       
  2726                     method = property;
       
  2727 
       
  2728                     if (setUp || tearDown) {
       
  2729                         method = createTest(property, setUp, tearDown);
       
  2730                     }
       
  2731 
       
  2732                     methods[testName] = sinon.test(method);
       
  2733                 } else {
       
  2734                     methods[testName] = tests[testName];
       
  2735                 }
       
  2736             }
       
  2737         }
       
  2738 
       
  2739         return methods;
       
  2740     }
       
  2741 
       
  2742     if (commonJSModule) {
       
  2743         module.exports = testCase;
       
  2744     } else {
       
  2745         sinon.testCase = testCase;
       
  2746     }
       
  2747 }(typeof sinon == "object" && sinon || null));
       
  2748 
       
  2749 /**
       
  2750  * @depend ../sinon.js
       
  2751  * @depend stub.js
       
  2752  */
       
  2753 /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
       
  2754 /*global module, require, sinon*/
       
  2755 /**
       
  2756  * Assertions matching the test spy retrieval interface.
       
  2757  *
       
  2758  * @author Christian Johansen (christian@cjohansen.no)
       
  2759  * @license BSD
       
  2760  *
       
  2761  * Copyright (c) 2010-2011 Christian Johansen
       
  2762  */
       
  2763 
       
  2764 (function (sinon) {
       
  2765     var commonJSModule = typeof module == "object" && typeof require == "function";
       
  2766     var slice = Array.prototype.slice;
       
  2767     var assert;
       
  2768 
       
  2769     if (!sinon && commonJSModule) {
       
  2770         sinon = require("../sinon");
       
  2771     }
       
  2772 
       
  2773     if (!sinon) {
       
  2774         return;
       
  2775     }
       
  2776 
       
  2777     function verifyIsStub() {
       
  2778         var method;
       
  2779 
       
  2780         for (var i = 0, l = arguments.length; i < l; ++i) {
       
  2781             method = arguments[i];
       
  2782 
       
  2783             if (!method) {
       
  2784                 assert.fail("fake is not a spy");
       
  2785             }
       
  2786 
       
  2787             if (typeof method != "function") {
       
  2788                 assert.fail(method + " is not a function");
       
  2789             }
       
  2790 
       
  2791             if (typeof method.getCall != "function") {
       
  2792                 assert.fail(method + " is not stubbed");
       
  2793             }
       
  2794         }
       
  2795     }
       
  2796 
       
  2797     function failAssertion(object, msg) {
       
  2798         var failMethod = object.fail || assert.fail;
       
  2799         failMethod.call(object, msg);
       
  2800     }
       
  2801 
       
  2802     function mirrorPropAsAssertion(name, method, message) {
       
  2803         if (arguments.length == 2) {
       
  2804             message = method;
       
  2805             method = name;
       
  2806         }
       
  2807 
       
  2808         assert[name] = function (fake) {
       
  2809             verifyIsStub(fake);
       
  2810 
       
  2811             var args = slice.call(arguments, 1);
       
  2812             var failed = false;
       
  2813 
       
  2814             if (typeof method == "function") {
       
  2815                 failed = !method(fake);
       
  2816             } else {
       
  2817                 failed = typeof fake[method] == "function" ?
       
  2818                     !fake[method].apply(fake, args) : !fake[method];
       
  2819             }
       
  2820 
       
  2821             if (failed) {
       
  2822                 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
       
  2823             } else {
       
  2824                 assert.pass(name);
       
  2825             }
       
  2826         };
       
  2827     }
       
  2828 
       
  2829     function exposedName(prefix, prop) {
       
  2830         return !prefix || /^fail/.test(prop) ? prop :
       
  2831             prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
       
  2832     };
       
  2833 
       
  2834     assert = {
       
  2835         failException: "AssertError",
       
  2836 
       
  2837         fail: function fail(message) {
       
  2838             var error = new Error(message);
       
  2839             error.name = this.failException || assert.failException;
       
  2840 
       
  2841             throw error;
       
  2842         },
       
  2843 
       
  2844         pass: function pass(assertion) {},
       
  2845 
       
  2846         callOrder: function assertCallOrder() {
       
  2847             verifyIsStub.apply(null, arguments);
       
  2848             var expected = "", actual = "";
       
  2849 
       
  2850             if (!sinon.calledInOrder(arguments)) {
       
  2851                 try {
       
  2852                     expected = [].join.call(arguments, ", ");
       
  2853                     actual = sinon.orderByFirstCall(slice.call(arguments)).join(", ");
       
  2854                 } catch (e) {}
       
  2855 
       
  2856                 failAssertion(this, "expected " + expected + " to be " +
       
  2857                               "called in order but were called as " + actual);
       
  2858             } else {
       
  2859                 assert.pass("callOrder");
       
  2860             }
       
  2861         },
       
  2862 
       
  2863         callCount: function assertCallCount(method, count) {
       
  2864             verifyIsStub(method);
       
  2865 
       
  2866             if (method.callCount != count) {
       
  2867                 var msg = "expected %n to be called " + sinon.timesInWords(count) +
       
  2868                     " but was called %c%C";
       
  2869                 failAssertion(this, method.printf(msg));
       
  2870             } else {
       
  2871                 assert.pass("callCount");
       
  2872             }
       
  2873         },
       
  2874 
       
  2875         expose: function expose(target, options) {
       
  2876             if (!target) {
       
  2877                 throw new TypeError("target is null or undefined");
       
  2878             }
       
  2879 
       
  2880             var o = options || {};
       
  2881             var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
       
  2882             var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
       
  2883 
       
  2884             for (var method in this) {
       
  2885                 if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
       
  2886                     target[exposedName(prefix, method)] = this[method];
       
  2887                 }
       
  2888             }
       
  2889 
       
  2890             return target;
       
  2891         }
       
  2892     };
       
  2893 
       
  2894     mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
       
  2895     mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
       
  2896                           "expected %n to not have been called but was called %c%C");
       
  2897     mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
       
  2898     mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
       
  2899     mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
       
  2900     mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
       
  2901     mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
       
  2902     mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
       
  2903     mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
       
  2904     mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
       
  2905     mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
       
  2906     mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
       
  2907     mirrorPropAsAssertion("threw", "%n did not throw exception%C");
       
  2908     mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
       
  2909 
       
  2910     if (commonJSModule) {
       
  2911         module.exports = assert;
       
  2912     } else {
       
  2913         sinon.assert = assert;
       
  2914     }
       
  2915 }(typeof sinon == "object" && sinon || null));
       
  2916