599fb470 by Gary Katsevman

Switch to use npm sinon

1 parent bf3cf7b6
1 /**
2 * Sinon.JS 1.9.0, 2014/03/05
3 *
4 * @author Christian Johansen (christian@cjohansen.no)
5 * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
6 *
7 * (The BSD License)
8 *
9 * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 *
15 * * Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * * Neither the name of Christian Johansen nor the names of his contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
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-2013 Christian Johansen
45 */
46
47 var sinon = (function (formatio) {
48 var div = typeof document != "undefined" && document.createElement("div");
49 var hasOwn = Object.prototype.hasOwnProperty;
50
51 function isDOMNode(obj) {
52 var success = false;
53
54 try {
55 obj.appendChild(div);
56 success = div.parentNode == obj;
57 } catch (e) {
58 return false;
59 } finally {
60 try {
61 obj.removeChild(div);
62 } catch (e) {
63 // Remove failed, not much we can do about that
64 }
65 }
66
67 return success;
68 }
69
70 function isElement(obj) {
71 return div && obj && obj.nodeType === 1 && isDOMNode(obj);
72 }
73
74 function isFunction(obj) {
75 return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
76 }
77
78 function mirrorProperties(target, source) {
79 for (var prop in source) {
80 if (!hasOwn.call(target, prop)) {
81 target[prop] = source[prop];
82 }
83 }
84 }
85
86 function isRestorable (obj) {
87 return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
88 }
89
90 var sinon = {
91 wrapMethod: function wrapMethod(object, property, method) {
92 if (!object) {
93 throw new TypeError("Should wrap property of object");
94 }
95
96 if (typeof method != "function") {
97 throw new TypeError("Method wrapper should be function");
98 }
99
100 var wrappedMethod = object[property],
101 error;
102
103 if (!isFunction(wrappedMethod)) {
104 error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
105 property + " as function");
106 }
107
108 if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
109 error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
110 }
111
112 if (wrappedMethod.calledBefore) {
113 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
114 error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
115 }
116
117 if (error) {
118 if (wrappedMethod._stack) {
119 error.stack += '\n--------------\n' + wrappedMethod._stack;
120 }
121 throw error;
122 }
123
124 // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
125 // when using hasOwn.call on objects from other frames.
126 var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
127 object[property] = method;
128 method.displayName = property;
129 // Set up a stack trace which can be used later to find what line of
130 // code the original method was created on.
131 method._stack = (new Error('Stack Trace for original')).stack;
132
133 method.restore = function () {
134 // For prototype properties try to reset by delete first.
135 // If this fails (ex: localStorage on mobile safari) then force a reset
136 // via direct assignment.
137 if (!owned) {
138 delete object[property];
139 }
140 if (object[property] === method) {
141 object[property] = wrappedMethod;
142 }
143 };
144
145 method.restore.sinon = true;
146 mirrorProperties(method, wrappedMethod);
147
148 return method;
149 },
150
151 extend: function extend(target) {
152 for (var i = 1, l = arguments.length; i < l; i += 1) {
153 for (var prop in arguments[i]) {
154 if (arguments[i].hasOwnProperty(prop)) {
155 target[prop] = arguments[i][prop];
156 }
157
158 // DONT ENUM bug, only care about toString
159 if (arguments[i].hasOwnProperty("toString") &&
160 arguments[i].toString != target.toString) {
161 target.toString = arguments[i].toString;
162 }
163 }
164 }
165
166 return target;
167 },
168
169 create: function create(proto) {
170 var F = function () {};
171 F.prototype = proto;
172 return new F();
173 },
174
175 deepEqual: function deepEqual(a, b) {
176 if (sinon.match && sinon.match.isMatcher(a)) {
177 return a.test(b);
178 }
179 if (typeof a != "object" || typeof b != "object") {
180 return a === b;
181 }
182
183 if (isElement(a) || isElement(b)) {
184 return a === b;
185 }
186
187 if (a === b) {
188 return true;
189 }
190
191 if ((a === null && b !== null) || (a !== null && b === null)) {
192 return false;
193 }
194
195 if (a instanceof RegExp && b instanceof RegExp) {
196 return (a.source === b.source) && (a.global === b.global) &&
197 (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
198 }
199
200 var aString = Object.prototype.toString.call(a);
201 if (aString != Object.prototype.toString.call(b)) {
202 return false;
203 }
204
205 if (aString == "[object Date]") {
206 return a.valueOf() === b.valueOf();
207 }
208
209 var prop, aLength = 0, bLength = 0;
210
211 if (aString == "[object Array]" && a.length !== b.length) {
212 return false;
213 }
214
215 for (prop in a) {
216 aLength += 1;
217
218 if (!deepEqual(a[prop], b[prop])) {
219 return false;
220 }
221 }
222
223 for (prop in b) {
224 bLength += 1;
225 }
226
227 return aLength == bLength;
228 },
229
230 functionName: function functionName(func) {
231 var name = func.displayName || func.name;
232
233 // Use function decomposition as a last resort to get function
234 // name. Does not rely on function decomposition to work - if it
235 // doesn't debugging will be slightly less informative
236 // (i.e. toString will say 'spy' rather than 'myFunc').
237 if (!name) {
238 var matches = func.toString().match(/function ([^\s\(]+)/);
239 name = matches && matches[1];
240 }
241
242 return name;
243 },
244
245 functionToString: function toString() {
246 if (this.getCall && this.callCount) {
247 var thisValue, prop, i = this.callCount;
248
249 while (i--) {
250 thisValue = this.getCall(i).thisValue;
251
252 for (prop in thisValue) {
253 if (thisValue[prop] === this) {
254 return prop;
255 }
256 }
257 }
258 }
259
260 return this.displayName || "sinon fake";
261 },
262
263 getConfig: function (custom) {
264 var config = {};
265 custom = custom || {};
266 var defaults = sinon.defaultConfig;
267
268 for (var prop in defaults) {
269 if (defaults.hasOwnProperty(prop)) {
270 config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
271 }
272 }
273
274 return config;
275 },
276
277 format: function (val) {
278 return "" + val;
279 },
280
281 defaultConfig: {
282 injectIntoThis: true,
283 injectInto: null,
284 properties: ["spy", "stub", "mock", "clock", "server", "requests"],
285 useFakeTimers: true,
286 useFakeServer: true
287 },
288
289 timesInWords: function timesInWords(count) {
290 return count == 1 && "once" ||
291 count == 2 && "twice" ||
292 count == 3 && "thrice" ||
293 (count || 0) + " times";
294 },
295
296 calledInOrder: function (spies) {
297 for (var i = 1, l = spies.length; i < l; i++) {
298 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
299 return false;
300 }
301 }
302
303 return true;
304 },
305
306 orderByFirstCall: function (spies) {
307 return spies.sort(function (a, b) {
308 // uuid, won't ever be equal
309 var aCall = a.getCall(0);
310 var bCall = b.getCall(0);
311 var aId = aCall && aCall.callId || -1;
312 var bId = bCall && bCall.callId || -1;
313
314 return aId < bId ? -1 : 1;
315 });
316 },
317
318 log: function () {},
319
320 logError: function (label, err) {
321 var msg = label + " threw exception: ";
322 sinon.log(msg + "[" + err.name + "] " + err.message);
323 if (err.stack) { sinon.log(err.stack); }
324
325 setTimeout(function () {
326 err.message = msg + err.message;
327 throw err;
328 }, 0);
329 },
330
331 typeOf: function (value) {
332 if (value === null) {
333 return "null";
334 }
335 else if (value === undefined) {
336 return "undefined";
337 }
338 var string = Object.prototype.toString.call(value);
339 return string.substring(8, string.length - 1).toLowerCase();
340 },
341
342 createStubInstance: function (constructor) {
343 if (typeof constructor !== "function") {
344 throw new TypeError("The constructor should be a function.");
345 }
346 return sinon.stub(sinon.create(constructor.prototype));
347 },
348
349 restore: function (object) {
350 if (object !== null && typeof object === "object") {
351 for (var prop in object) {
352 if (isRestorable(object[prop])) {
353 object[prop].restore();
354 }
355 }
356 }
357 else if (isRestorable(object)) {
358 object.restore();
359 }
360 }
361 };
362
363 var isNode = typeof module !== "undefined" && module.exports;
364 var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
365
366 if (isAMD) {
367 define(function(){
368 return sinon;
369 });
370 } else if (isNode) {
371 try {
372 formatio = require("formatio");
373 } catch (e) {}
374 module.exports = sinon;
375 module.exports.spy = require("./sinon/spy");
376 module.exports.spyCall = require("./sinon/call");
377 module.exports.behavior = require("./sinon/behavior");
378 module.exports.stub = require("./sinon/stub");
379 module.exports.mock = require("./sinon/mock");
380 module.exports.collection = require("./sinon/collection");
381 module.exports.assert = require("./sinon/assert");
382 module.exports.sandbox = require("./sinon/sandbox");
383 module.exports.test = require("./sinon/test");
384 module.exports.testCase = require("./sinon/test_case");
385 module.exports.assert = require("./sinon/assert");
386 module.exports.match = require("./sinon/match");
387 }
388
389 if (formatio) {
390 var formatter = formatio.configure({ quoteStrings: false });
391 sinon.format = function () {
392 return formatter.ascii.apply(formatter, arguments);
393 };
394 } else if (isNode) {
395 try {
396 var util = require("util");
397 sinon.format = function (value) {
398 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
399 };
400 } catch (e) {
401 /* Node, but no util module - would be very old, but better safe than
402 sorry */
403 }
404 }
405
406 return sinon;
407 }(typeof formatio == "object" && formatio));
408
409 /*jslint eqeqeq: false, onevar: false*/
410 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
411 /**
412 * Minimal Event interface implementation
413 *
414 * Original implementation by Sven Fuchs: https://gist.github.com/995028
415 * Modifications and tests by Christian Johansen.
416 *
417 * @author Sven Fuchs (svenfuchs@artweb-design.de)
418 * @author Christian Johansen (christian@cjohansen.no)
419 * @license BSD
420 *
421 * Copyright (c) 2011 Sven Fuchs, Christian Johansen
422 */
423
424 if (typeof sinon == "undefined") {
425 this.sinon = {};
426 }
427
428 (function () {
429 var push = [].push;
430
431 sinon.Event = function Event(type, bubbles, cancelable, target) {
432 this.initEvent(type, bubbles, cancelable, target);
433 };
434
435 sinon.Event.prototype = {
436 initEvent: function(type, bubbles, cancelable, target) {
437 this.type = type;
438 this.bubbles = bubbles;
439 this.cancelable = cancelable;
440 this.target = target;
441 },
442
443 stopPropagation: function () {},
444
445 preventDefault: function () {
446 this.defaultPrevented = true;
447 }
448 };
449
450 sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
451 this.initEvent(type, false, false, target);
452 this.loaded = progressEventRaw.loaded || null;
453 this.total = progressEventRaw.total || null;
454 };
455
456 sinon.ProgressEvent.prototype = new sinon.Event();
457
458 sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
459
460 sinon.CustomEvent = function CustomEvent(type, customData, target) {
461 this.initEvent(type, false, false, target);
462 this.detail = customData.detail || null;
463 };
464
465 sinon.CustomEvent.prototype = new sinon.Event();
466
467 sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
468
469 sinon.EventTarget = {
470 addEventListener: function addEventListener(event, listener) {
471 this.eventListeners = this.eventListeners || {};
472 this.eventListeners[event] = this.eventListeners[event] || [];
473 push.call(this.eventListeners[event], listener);
474 },
475
476 removeEventListener: function removeEventListener(event, listener) {
477 var listeners = this.eventListeners && this.eventListeners[event] || [];
478
479 for (var i = 0, l = listeners.length; i < l; ++i) {
480 if (listeners[i] == listener) {
481 return listeners.splice(i, 1);
482 }
483 }
484 },
485
486 dispatchEvent: function dispatchEvent(event) {
487 var type = event.type;
488 var listeners = this.eventListeners && this.eventListeners[type] || [];
489
490 for (var i = 0; i < listeners.length; i++) {
491 if (typeof listeners[i] == "function") {
492 listeners[i].call(this, event);
493 } else {
494 listeners[i].handleEvent(event);
495 }
496 }
497
498 return !!event.defaultPrevented;
499 }
500 };
501 }());
502
503 /**
504 * @depend ../../sinon.js
505 * @depend event.js
506 */
507 /*jslint eqeqeq: false, onevar: false*/
508 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
509 /**
510 * Fake XMLHttpRequest object
511 *
512 * @author Christian Johansen (christian@cjohansen.no)
513 * @license BSD
514 *
515 * Copyright (c) 2010-2013 Christian Johansen
516 */
517
518 // wrapper for global
519 (function(global) {
520 if (typeof sinon === "undefined") {
521 global.sinon = {};
522 }
523
524 var supportsProgress = typeof ProgressEvent !== "undefined";
525 var supportsCustomEvent = typeof CustomEvent !== "undefined";
526 sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
527 var xhr = sinon.xhr;
528 xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
529 xhr.GlobalActiveXObject = global.ActiveXObject;
530 xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
531 xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
532 xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
533 ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
534 xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
535
536 /*jsl:ignore*/
537 var unsafeHeaders = {
538 "Accept-Charset": true,
539 "Accept-Encoding": true,
540 "Connection": true,
541 "Content-Length": true,
542 "Cookie": true,
543 "Cookie2": true,
544 "Content-Transfer-Encoding": true,
545 "Date": true,
546 "Expect": true,
547 "Host": true,
548 "Keep-Alive": true,
549 "Referer": true,
550 "TE": true,
551 "Trailer": true,
552 "Transfer-Encoding": true,
553 "Upgrade": true,
554 "User-Agent": true,
555 "Via": true
556 };
557 /*jsl:end*/
558
559 function FakeXMLHttpRequest() {
560 this.readyState = FakeXMLHttpRequest.UNSENT;
561 this.requestHeaders = {};
562 this.requestBody = null;
563 this.status = 0;
564 this.statusText = "";
565 this.upload = new UploadProgress();
566 if (sinon.xhr.supportsCORS) {
567 this.withCredentials = false;
568 }
569
570
571 var xhr = this;
572 var events = ["loadstart", "load", "abort", "loadend"];
573
574 function addEventListener(eventName) {
575 xhr.addEventListener(eventName, function (event) {
576 var listener = xhr["on" + eventName];
577
578 if (listener && typeof listener == "function") {
579 listener.call(this, event);
580 }
581 });
582 }
583
584 for (var i = events.length - 1; i >= 0; i--) {
585 addEventListener(events[i]);
586 }
587
588 if (typeof FakeXMLHttpRequest.onCreate == "function") {
589 FakeXMLHttpRequest.onCreate(this);
590 }
591 }
592
593 // An upload object is created for each
594 // FakeXMLHttpRequest and allows upload
595 // events to be simulated using uploadProgress
596 // and uploadError.
597 function UploadProgress() {
598 this.eventListeners = {
599 "progress": [],
600 "load": [],
601 "abort": [],
602 "error": []
603 }
604 }
605
606 UploadProgress.prototype.addEventListener = function(event, listener) {
607 this.eventListeners[event].push(listener);
608 };
609
610 UploadProgress.prototype.removeEventListener = function(event, listener) {
611 var listeners = this.eventListeners[event] || [];
612
613 for (var i = 0, l = listeners.length; i < l; ++i) {
614 if (listeners[i] == listener) {
615 return listeners.splice(i, 1);
616 }
617 }
618 };
619
620 UploadProgress.prototype.dispatchEvent = function(event) {
621 var listeners = this.eventListeners[event.type] || [];
622
623 for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
624 listener(event);
625 }
626 };
627
628 function verifyState(xhr) {
629 if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
630 throw new Error("INVALID_STATE_ERR");
631 }
632
633 if (xhr.sendFlag) {
634 throw new Error("INVALID_STATE_ERR");
635 }
636 }
637
638 // filtering to enable a white-list version of Sinon FakeXhr,
639 // where whitelisted requests are passed through to real XHR
640 function each(collection, callback) {
641 if (!collection) return;
642 for (var i = 0, l = collection.length; i < l; i += 1) {
643 callback(collection[i]);
644 }
645 }
646 function some(collection, callback) {
647 for (var index = 0; index < collection.length; index++) {
648 if(callback(collection[index]) === true) return true;
649 }
650 return false;
651 }
652 // largest arity in XHR is 5 - XHR#open
653 var apply = function(obj,method,args) {
654 switch(args.length) {
655 case 0: return obj[method]();
656 case 1: return obj[method](args[0]);
657 case 2: return obj[method](args[0],args[1]);
658 case 3: return obj[method](args[0],args[1],args[2]);
659 case 4: return obj[method](args[0],args[1],args[2],args[3]);
660 case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
661 }
662 };
663
664 FakeXMLHttpRequest.filters = [];
665 FakeXMLHttpRequest.addFilter = function(fn) {
666 this.filters.push(fn)
667 };
668 var IE6Re = /MSIE 6/;
669 FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
670 var xhr = new sinon.xhr.workingXHR();
671 each(["open","setRequestHeader","send","abort","getResponseHeader",
672 "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
673 function(method) {
674 fakeXhr[method] = function() {
675 return apply(xhr,method,arguments);
676 };
677 });
678
679 var copyAttrs = function(args) {
680 each(args, function(attr) {
681 try {
682 fakeXhr[attr] = xhr[attr]
683 } catch(e) {
684 if(!IE6Re.test(navigator.userAgent)) throw e;
685 }
686 });
687 };
688
689 var stateChange = function() {
690 fakeXhr.readyState = xhr.readyState;
691 if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
692 copyAttrs(["status","statusText"]);
693 }
694 if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
695 copyAttrs(["responseText"]);
696 }
697 if(xhr.readyState === FakeXMLHttpRequest.DONE) {
698 copyAttrs(["responseXML"]);
699 }
700 if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
701 };
702 if(xhr.addEventListener) {
703 for(var event in fakeXhr.eventListeners) {
704 if(fakeXhr.eventListeners.hasOwnProperty(event)) {
705 each(fakeXhr.eventListeners[event],function(handler) {
706 xhr.addEventListener(event, handler);
707 });
708 }
709 }
710 xhr.addEventListener("readystatechange",stateChange);
711 } else {
712 xhr.onreadystatechange = stateChange;
713 }
714 apply(xhr,"open",xhrArgs);
715 };
716 FakeXMLHttpRequest.useFilters = false;
717
718 function verifyRequestOpened(xhr) {
719 if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
720 throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
721 }
722 }
723
724 function verifyRequestSent(xhr) {
725 if (xhr.readyState == FakeXMLHttpRequest.DONE) {
726 throw new Error("Request done");
727 }
728 }
729
730 function verifyHeadersReceived(xhr) {
731 if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
732 throw new Error("No headers received");
733 }
734 }
735
736 function verifyResponseBodyType(body) {
737 if (typeof body != "string") {
738 var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
739 body + ", which is not a string.");
740 error.name = "InvalidBodyException";
741 throw error;
742 }
743 }
744
745 sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
746 async: true,
747
748 open: function open(method, url, async, username, password) {
749 this.method = method;
750 this.url = url;
751 this.async = typeof async == "boolean" ? async : true;
752 this.username = username;
753 this.password = password;
754 this.responseText = null;
755 this.responseXML = null;
756 this.requestHeaders = {};
757 this.sendFlag = false;
758 if(sinon.FakeXMLHttpRequest.useFilters === true) {
759 var xhrArgs = arguments;
760 var defake = some(FakeXMLHttpRequest.filters,function(filter) {
761 return filter.apply(this,xhrArgs)
762 });
763 if (defake) {
764 return sinon.FakeXMLHttpRequest.defake(this,arguments);
765 }
766 }
767 this.readyStateChange(FakeXMLHttpRequest.OPENED);
768 },
769
770 readyStateChange: function readyStateChange(state) {
771 this.readyState = state;
772
773 if (typeof this.onreadystatechange == "function") {
774 try {
775 this.onreadystatechange();
776 } catch (e) {
777 sinon.logError("Fake XHR onreadystatechange handler", e);
778 }
779 }
780
781 this.dispatchEvent(new sinon.Event("readystatechange"));
782
783 switch (this.readyState) {
784 case FakeXMLHttpRequest.DONE:
785 this.dispatchEvent(new sinon.Event("load", false, false, this));
786 this.dispatchEvent(new sinon.Event("loadend", false, false, this));
787 this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
788 if (supportsProgress) {
789 this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
790 }
791 break;
792 }
793 },
794
795 setRequestHeader: function setRequestHeader(header, value) {
796 verifyState(this);
797
798 if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
799 throw new Error("Refused to set unsafe header \"" + header + "\"");
800 }
801
802 if (this.requestHeaders[header]) {
803 this.requestHeaders[header] += "," + value;
804 } else {
805 this.requestHeaders[header] = value;
806 }
807 },
808
809 // Helps testing
810 setResponseHeaders: function setResponseHeaders(headers) {
811 verifyRequestOpened(this);
812 this.responseHeaders = {};
813
814 for (var header in headers) {
815 if (headers.hasOwnProperty(header)) {
816 this.responseHeaders[header] = headers[header];
817 }
818 }
819
820 if (this.async) {
821 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
822 } else {
823 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
824 }
825 },
826
827 // Currently treats ALL data as a DOMString (i.e. no Document)
828 send: function send(data) {
829 verifyState(this);
830
831 if (!/^(get|head)$/i.test(this.method)) {
832 if (this.requestHeaders["Content-Type"]) {
833 var value = this.requestHeaders["Content-Type"].split(";");
834 this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
835 } else {
836 this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
837 }
838
839 this.requestBody = data;
840 }
841
842 this.errorFlag = false;
843 this.sendFlag = this.async;
844 this.readyStateChange(FakeXMLHttpRequest.OPENED);
845
846 if (typeof this.onSend == "function") {
847 this.onSend(this);
848 }
849
850 this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
851 },
852
853 abort: function abort() {
854 this.aborted = true;
855 this.responseText = null;
856 this.errorFlag = true;
857 this.requestHeaders = {};
858
859 if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
860 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
861 this.sendFlag = false;
862 }
863
864 this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
865
866 this.dispatchEvent(new sinon.Event("abort", false, false, this));
867
868 this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
869
870 if (typeof this.onerror === "function") {
871 this.onerror();
872 }
873 },
874
875 getResponseHeader: function getResponseHeader(header) {
876 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
877 return null;
878 }
879
880 if (/^Set-Cookie2?$/i.test(header)) {
881 return null;
882 }
883
884 header = header.toLowerCase();
885
886 for (var h in this.responseHeaders) {
887 if (h.toLowerCase() == header) {
888 return this.responseHeaders[h];
889 }
890 }
891
892 return null;
893 },
894
895 getAllResponseHeaders: function getAllResponseHeaders() {
896 if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
897 return "";
898 }
899
900 var headers = "";
901
902 for (var header in this.responseHeaders) {
903 if (this.responseHeaders.hasOwnProperty(header) &&
904 !/^Set-Cookie2?$/i.test(header)) {
905 headers += header + ": " + this.responseHeaders[header] + "\r\n";
906 }
907 }
908
909 return headers;
910 },
911
912 setResponseBody: function setResponseBody(body) {
913 verifyRequestSent(this);
914 verifyHeadersReceived(this);
915 verifyResponseBodyType(body);
916
917 var chunkSize = this.chunkSize || 10;
918 var index = 0;
919 this.responseText = "";
920
921 do {
922 if (this.async) {
923 this.readyStateChange(FakeXMLHttpRequest.LOADING);
924 }
925
926 this.responseText += body.substring(index, index + chunkSize);
927 index += chunkSize;
928 } while (index < body.length);
929
930 var type = this.getResponseHeader("Content-Type");
931
932 if (this.responseText &&
933 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
934 try {
935 this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
936 } catch (e) {
937 // Unable to parse XML - no biggie
938 }
939 }
940
941 if (this.async) {
942 this.readyStateChange(FakeXMLHttpRequest.DONE);
943 } else {
944 this.readyState = FakeXMLHttpRequest.DONE;
945 }
946 },
947
948 respond: function respond(status, headers, body) {
949 this.status = typeof status == "number" ? status : 200;
950 this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
951 this.setResponseHeaders(headers || {});
952 this.setResponseBody(body || "");
953 },
954
955 uploadProgress: function uploadProgress(progressEventRaw) {
956 if (supportsProgress) {
957 this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
958 }
959 },
960
961 uploadError: function uploadError(error) {
962 if (supportsCustomEvent) {
963 this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
964 }
965 }
966 });
967
968 sinon.extend(FakeXMLHttpRequest, {
969 UNSENT: 0,
970 OPENED: 1,
971 HEADERS_RECEIVED: 2,
972 LOADING: 3,
973 DONE: 4
974 });
975
976 // Borrowed from JSpec
977 FakeXMLHttpRequest.parseXML = function parseXML(text) {
978 var xmlDoc;
979
980 if (typeof DOMParser != "undefined") {
981 var parser = new DOMParser();
982 xmlDoc = parser.parseFromString(text, "text/xml");
983 } else {
984 xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
985 xmlDoc.async = "false";
986 xmlDoc.loadXML(text);
987 }
988
989 return xmlDoc;
990 };
991
992 FakeXMLHttpRequest.statusCodes = {
993 100: "Continue",
994 101: "Switching Protocols",
995 200: "OK",
996 201: "Created",
997 202: "Accepted",
998 203: "Non-Authoritative Information",
999 204: "No Content",
1000 205: "Reset Content",
1001 206: "Partial Content",
1002 300: "Multiple Choice",
1003 301: "Moved Permanently",
1004 302: "Found",
1005 303: "See Other",
1006 304: "Not Modified",
1007 305: "Use Proxy",
1008 307: "Temporary Redirect",
1009 400: "Bad Request",
1010 401: "Unauthorized",
1011 402: "Payment Required",
1012 403: "Forbidden",
1013 404: "Not Found",
1014 405: "Method Not Allowed",
1015 406: "Not Acceptable",
1016 407: "Proxy Authentication Required",
1017 408: "Request Timeout",
1018 409: "Conflict",
1019 410: "Gone",
1020 411: "Length Required",
1021 412: "Precondition Failed",
1022 413: "Request Entity Too Large",
1023 414: "Request-URI Too Long",
1024 415: "Unsupported Media Type",
1025 416: "Requested Range Not Satisfiable",
1026 417: "Expectation Failed",
1027 422: "Unprocessable Entity",
1028 500: "Internal Server Error",
1029 501: "Not Implemented",
1030 502: "Bad Gateway",
1031 503: "Service Unavailable",
1032 504: "Gateway Timeout",
1033 505: "HTTP Version Not Supported"
1034 };
1035
1036 sinon.useFakeXMLHttpRequest = function () {
1037 sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
1038 if (xhr.supportsXHR) {
1039 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
1040 }
1041
1042 if (xhr.supportsActiveX) {
1043 global.ActiveXObject = xhr.GlobalActiveXObject;
1044 }
1045
1046 delete sinon.FakeXMLHttpRequest.restore;
1047
1048 if (keepOnCreate !== true) {
1049 delete sinon.FakeXMLHttpRequest.onCreate;
1050 }
1051 };
1052 if (xhr.supportsXHR) {
1053 global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
1054 }
1055
1056 if (xhr.supportsActiveX) {
1057 global.ActiveXObject = function ActiveXObject(objId) {
1058 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
1059
1060 return new sinon.FakeXMLHttpRequest();
1061 }
1062
1063 return new xhr.GlobalActiveXObject(objId);
1064 };
1065 }
1066
1067 return sinon.FakeXMLHttpRequest;
1068 };
1069
1070 sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
1071
1072 })(typeof global === "object" ? global : this);
1073
1074 if (typeof module !== 'undefined' && module.exports) {
1075 module.exports = sinon;
1076 }
1077
1078 /**
1079 * @depend fake_xml_http_request.js
1080 */
1081 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
1082 /*global module, require, window*/
1083 /**
1084 * The Sinon "server" mimics a web server that receives requests from
1085 * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
1086 * both synchronously and asynchronously. To respond synchronuously, canned
1087 * answers have to be provided upfront.
1088 *
1089 * @author Christian Johansen (christian@cjohansen.no)
1090 * @license BSD
1091 *
1092 * Copyright (c) 2010-2013 Christian Johansen
1093 */
1094
1095 if (typeof sinon == "undefined") {
1096 var sinon = {};
1097 }
1098
1099 sinon.fakeServer = (function () {
1100 var push = [].push;
1101 function F() {}
1102
1103 function create(proto) {
1104 F.prototype = proto;
1105 return new F();
1106 }
1107
1108 function responseArray(handler) {
1109 var response = handler;
1110
1111 if (Object.prototype.toString.call(handler) != "[object Array]") {
1112 response = [200, {}, handler];
1113 }
1114
1115 if (typeof response[2] != "string") {
1116 throw new TypeError("Fake server response body should be string, but was " +
1117 typeof response[2]);
1118 }
1119
1120 return response;
1121 }
1122
1123 var wloc = typeof window !== "undefined" ? window.location : {};
1124 var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
1125
1126 function matchOne(response, reqMethod, reqUrl) {
1127 var rmeth = response.method;
1128 var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
1129 var url = response.url;
1130 var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
1131
1132 return matchMethod && matchUrl;
1133 }
1134
1135 function match(response, request) {
1136 var requestUrl = request.url;
1137
1138 if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
1139 requestUrl = requestUrl.replace(rCurrLoc, "");
1140 }
1141
1142 if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
1143 if (typeof response.response == "function") {
1144 var ru = response.url;
1145 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
1146 return response.response.apply(response, args);
1147 }
1148
1149 return true;
1150 }
1151
1152 return false;
1153 }
1154
1155 function log(response, request) {
1156 var str;
1157
1158 str = "Request:\n" + sinon.format(request) + "\n\n";
1159 str += "Response:\n" + sinon.format(response) + "\n\n";
1160
1161 sinon.log(str);
1162 }
1163
1164 return {
1165 create: function () {
1166 var server = create(this);
1167 this.xhr = sinon.useFakeXMLHttpRequest();
1168 server.requests = [];
1169
1170 this.xhr.onCreate = function (xhrObj) {
1171 server.addRequest(xhrObj);
1172 };
1173
1174 return server;
1175 },
1176
1177 addRequest: function addRequest(xhrObj) {
1178 var server = this;
1179 push.call(this.requests, xhrObj);
1180
1181 xhrObj.onSend = function () {
1182 server.handleRequest(this);
1183
1184 if (server.autoRespond && !server.responding) {
1185 setTimeout(function () {
1186 server.responding = false;
1187 server.respond();
1188 }, server.autoRespondAfter || 10);
1189
1190 server.responding = true;
1191 }
1192 };
1193 },
1194
1195 getHTTPMethod: function getHTTPMethod(request) {
1196 if (this.fakeHTTPMethods && /post/i.test(request.method)) {
1197 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
1198 return !!matches ? matches[1] : request.method;
1199 }
1200
1201 return request.method;
1202 },
1203
1204 handleRequest: function handleRequest(xhr) {
1205 if (xhr.async) {
1206 if (!this.queue) {
1207 this.queue = [];
1208 }
1209
1210 push.call(this.queue, xhr);
1211 } else {
1212 this.processRequest(xhr);
1213 }
1214 },
1215
1216 respondWith: function respondWith(method, url, body) {
1217 if (arguments.length == 1 && typeof method != "function") {
1218 this.response = responseArray(method);
1219 return;
1220 }
1221
1222 if (!this.responses) { this.responses = []; }
1223
1224 if (arguments.length == 1) {
1225 body = method;
1226 url = method = null;
1227 }
1228
1229 if (arguments.length == 2) {
1230 body = url;
1231 url = method;
1232 method = null;
1233 }
1234
1235 push.call(this.responses, {
1236 method: method,
1237 url: url,
1238 response: typeof body == "function" ? body : responseArray(body)
1239 });
1240 },
1241
1242 respond: function respond() {
1243 if (arguments.length > 0) this.respondWith.apply(this, arguments);
1244 var queue = this.queue || [];
1245 var requests = queue.splice(0);
1246 var request;
1247
1248 while(request = requests.shift()) {
1249 this.processRequest(request);
1250 }
1251 },
1252
1253 processRequest: function processRequest(request) {
1254 try {
1255 if (request.aborted) {
1256 return;
1257 }
1258
1259 var response = this.response || [404, {}, ""];
1260
1261 if (this.responses) {
1262 for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
1263 if (match.call(this, this.responses[i], request)) {
1264 response = this.responses[i].response;
1265 break;
1266 }
1267 }
1268 }
1269
1270 if (request.readyState != 4) {
1271 log(response, request);
1272
1273 request.respond(response[0], response[1], response[2]);
1274 }
1275 } catch (e) {
1276 sinon.logError("Fake server request processing", e);
1277 }
1278 },
1279
1280 restore: function restore() {
1281 return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
1282 }
1283 };
1284 }());
1285
1286 if (typeof module !== 'undefined' && module.exports) {
1287 module.exports = sinon;
1288 }
1289
1290 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
1291 /*global module, require, window*/
1292 /**
1293 * Fake timer API
1294 * setTimeout
1295 * setInterval
1296 * clearTimeout
1297 * clearInterval
1298 * tick
1299 * reset
1300 * Date
1301 *
1302 * Inspired by jsUnitMockTimeOut from JsUnit
1303 *
1304 * @author Christian Johansen (christian@cjohansen.no)
1305 * @license BSD
1306 *
1307 * Copyright (c) 2010-2013 Christian Johansen
1308 */
1309
1310 if (typeof sinon == "undefined") {
1311 var sinon = {};
1312 }
1313
1314 (function (global) {
1315 var id = 1;
1316
1317 function addTimer(args, recurring) {
1318 if (args.length === 0) {
1319 throw new Error("Function requires at least 1 parameter");
1320 }
1321
1322 if (typeof args[0] === "undefined") {
1323 throw new Error("Callback must be provided to timer calls");
1324 }
1325
1326 var toId = id++;
1327 var delay = args[1] || 0;
1328
1329 if (!this.timeouts) {
1330 this.timeouts = {};
1331 }
1332
1333 this.timeouts[toId] = {
1334 id: toId,
1335 func: args[0],
1336 callAt: this.now + delay,
1337 invokeArgs: Array.prototype.slice.call(args, 2)
1338 };
1339
1340 if (recurring === true) {
1341 this.timeouts[toId].interval = delay;
1342 }
1343
1344 return toId;
1345 }
1346
1347 function parseTime(str) {
1348 if (!str) {
1349 return 0;
1350 }
1351
1352 var strings = str.split(":");
1353 var l = strings.length, i = l;
1354 var ms = 0, parsed;
1355
1356 if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
1357 throw new Error("tick only understands numbers and 'h:m:s'");
1358 }
1359
1360 while (i--) {
1361 parsed = parseInt(strings[i], 10);
1362
1363 if (parsed >= 60) {
1364 throw new Error("Invalid time " + str);
1365 }
1366
1367 ms += parsed * Math.pow(60, (l - i - 1));
1368 }
1369
1370 return ms * 1000;
1371 }
1372
1373 function createObject(object) {
1374 var newObject;
1375
1376 if (Object.create) {
1377 newObject = Object.create(object);
1378 } else {
1379 var F = function () {};
1380 F.prototype = object;
1381 newObject = new F();
1382 }
1383
1384 newObject.Date.clock = newObject;
1385 return newObject;
1386 }
1387
1388 sinon.clock = {
1389 now: 0,
1390
1391 create: function create(now) {
1392 var clock = createObject(this);
1393
1394 if (typeof now == "number") {
1395 clock.now = now;
1396 }
1397
1398 if (!!now && typeof now == "object") {
1399 throw new TypeError("now should be milliseconds since UNIX epoch");
1400 }
1401
1402 return clock;
1403 },
1404
1405 setTimeout: function setTimeout(callback, timeout) {
1406 return addTimer.call(this, arguments, false);
1407 },
1408
1409 clearTimeout: function clearTimeout(timerId) {
1410 if (!this.timeouts) {
1411 this.timeouts = [];
1412 }
1413
1414 if (timerId in this.timeouts) {
1415 delete this.timeouts[timerId];
1416 }
1417 },
1418
1419 setInterval: function setInterval(callback, timeout) {
1420 return addTimer.call(this, arguments, true);
1421 },
1422
1423 clearInterval: function clearInterval(timerId) {
1424 this.clearTimeout(timerId);
1425 },
1426
1427 setImmediate: function setImmediate(callback) {
1428 var passThruArgs = Array.prototype.slice.call(arguments, 1);
1429
1430 return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
1431 },
1432
1433 clearImmediate: function clearImmediate(timerId) {
1434 this.clearTimeout(timerId);
1435 },
1436
1437 tick: function tick(ms) {
1438 ms = typeof ms == "number" ? ms : parseTime(ms);
1439 var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
1440 var timer = this.firstTimerInRange(tickFrom, tickTo);
1441
1442 var firstException;
1443 while (timer && tickFrom <= tickTo) {
1444 if (this.timeouts[timer.id]) {
1445 tickFrom = this.now = timer.callAt;
1446 try {
1447 this.callTimer(timer);
1448 } catch (e) {
1449 firstException = firstException || e;
1450 }
1451 }
1452
1453 timer = this.firstTimerInRange(previous, tickTo);
1454 previous = tickFrom;
1455 }
1456
1457 this.now = tickTo;
1458
1459 if (firstException) {
1460 throw firstException;
1461 }
1462
1463 return this.now;
1464 },
1465
1466 firstTimerInRange: function (from, to) {
1467 var timer, smallest = null, originalTimer;
1468
1469 for (var id in this.timeouts) {
1470 if (this.timeouts.hasOwnProperty(id)) {
1471 if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
1472 continue;
1473 }
1474
1475 if (smallest === null || this.timeouts[id].callAt < smallest) {
1476 originalTimer = this.timeouts[id];
1477 smallest = this.timeouts[id].callAt;
1478
1479 timer = {
1480 func: this.timeouts[id].func,
1481 callAt: this.timeouts[id].callAt,
1482 interval: this.timeouts[id].interval,
1483 id: this.timeouts[id].id,
1484 invokeArgs: this.timeouts[id].invokeArgs
1485 };
1486 }
1487 }
1488 }
1489
1490 return timer || null;
1491 },
1492
1493 callTimer: function (timer) {
1494 if (typeof timer.interval == "number") {
1495 this.timeouts[timer.id].callAt += timer.interval;
1496 } else {
1497 delete this.timeouts[timer.id];
1498 }
1499
1500 try {
1501 if (typeof timer.func == "function") {
1502 timer.func.apply(null, timer.invokeArgs);
1503 } else {
1504 eval(timer.func);
1505 }
1506 } catch (e) {
1507 var exception = e;
1508 }
1509
1510 if (!this.timeouts[timer.id]) {
1511 if (exception) {
1512 throw exception;
1513 }
1514 return;
1515 }
1516
1517 if (exception) {
1518 throw exception;
1519 }
1520 },
1521
1522 reset: function reset() {
1523 this.timeouts = {};
1524 },
1525
1526 Date: (function () {
1527 var NativeDate = Date;
1528
1529 function ClockDate(year, month, date, hour, minute, second, ms) {
1530 // Defensive and verbose to avoid potential harm in passing
1531 // explicit undefined when user does not pass argument
1532 switch (arguments.length) {
1533 case 0:
1534 return new NativeDate(ClockDate.clock.now);
1535 case 1:
1536 return new NativeDate(year);
1537 case 2:
1538 return new NativeDate(year, month);
1539 case 3:
1540 return new NativeDate(year, month, date);
1541 case 4:
1542 return new NativeDate(year, month, date, hour);
1543 case 5:
1544 return new NativeDate(year, month, date, hour, minute);
1545 case 6:
1546 return new NativeDate(year, month, date, hour, minute, second);
1547 default:
1548 return new NativeDate(year, month, date, hour, minute, second, ms);
1549 }
1550 }
1551
1552 return mirrorDateProperties(ClockDate, NativeDate);
1553 }())
1554 };
1555
1556 function mirrorDateProperties(target, source) {
1557 if (source.now) {
1558 target.now = function now() {
1559 return target.clock.now;
1560 };
1561 } else {
1562 delete target.now;
1563 }
1564
1565 if (source.toSource) {
1566 target.toSource = function toSource() {
1567 return source.toSource();
1568 };
1569 } else {
1570 delete target.toSource;
1571 }
1572
1573 target.toString = function toString() {
1574 return source.toString();
1575 };
1576
1577 target.prototype = source.prototype;
1578 target.parse = source.parse;
1579 target.UTC = source.UTC;
1580 target.prototype.toUTCString = source.prototype.toUTCString;
1581
1582 for (var prop in source) {
1583 if (source.hasOwnProperty(prop)) {
1584 target[prop] = source[prop];
1585 }
1586 }
1587
1588 return target;
1589 }
1590
1591 var methods = ["Date", "setTimeout", "setInterval",
1592 "clearTimeout", "clearInterval"];
1593
1594 if (typeof global.setImmediate !== "undefined") {
1595 methods.push("setImmediate");
1596 }
1597
1598 if (typeof global.clearImmediate !== "undefined") {
1599 methods.push("clearImmediate");
1600 }
1601
1602 function restore() {
1603 var method;
1604
1605 for (var i = 0, l = this.methods.length; i < l; i++) {
1606 method = this.methods[i];
1607
1608 if (global[method].hadOwnProperty) {
1609 global[method] = this["_" + method];
1610 } else {
1611 try {
1612 delete global[method];
1613 } catch (e) {}
1614 }
1615 }
1616
1617 // Prevent multiple executions which will completely remove these props
1618 this.methods = [];
1619 }
1620
1621 function stubGlobal(method, clock) {
1622 clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
1623 clock["_" + method] = global[method];
1624
1625 if (method == "Date") {
1626 var date = mirrorDateProperties(clock[method], global[method]);
1627 global[method] = date;
1628 } else {
1629 global[method] = function () {
1630 return clock[method].apply(clock, arguments);
1631 };
1632
1633 for (var prop in clock[method]) {
1634 if (clock[method].hasOwnProperty(prop)) {
1635 global[method][prop] = clock[method][prop];
1636 }
1637 }
1638 }
1639
1640 global[method].clock = clock;
1641 }
1642
1643 sinon.useFakeTimers = function useFakeTimers(now) {
1644 var clock = sinon.clock.create(now);
1645 clock.restore = restore;
1646 clock.methods = Array.prototype.slice.call(arguments,
1647 typeof now == "number" ? 1 : 0);
1648
1649 if (clock.methods.length === 0) {
1650 clock.methods = methods;
1651 }
1652
1653 for (var i = 0, l = clock.methods.length; i < l; i++) {
1654 stubGlobal(clock.methods[i], clock);
1655 }
1656
1657 return clock;
1658 };
1659 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
1660
1661 sinon.timers = {
1662 setTimeout: setTimeout,
1663 clearTimeout: clearTimeout,
1664 setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
1665 clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
1666 setInterval: setInterval,
1667 clearInterval: clearInterval,
1668 Date: Date
1669 };
1670
1671 if (typeof module !== 'undefined' && module.exports) {
1672 module.exports = sinon;
1673 }
1674
1675 /**
1676 * @depend fake_server.js
1677 * @depend fake_timers.js
1678 */
1679 /*jslint browser: true, eqeqeq: false, onevar: false*/
1680 /*global sinon*/
1681 /**
1682 * Add-on for sinon.fakeServer that automatically handles a fake timer along with
1683 * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
1684 * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
1685 * it polls the object for completion with setInterval. Dispite the direct
1686 * motivation, there is nothing jQuery-specific in this file, so it can be used
1687 * in any environment where the ajax implementation depends on setInterval or
1688 * setTimeout.
1689 *
1690 * @author Christian Johansen (christian@cjohansen.no)
1691 * @license BSD
1692 *
1693 * Copyright (c) 2010-2013 Christian Johansen
1694 */
1695
1696 (function () {
1697 function Server() {}
1698 Server.prototype = sinon.fakeServer;
1699
1700 sinon.fakeServerWithClock = new Server();
1701
1702 sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
1703 if (xhr.async) {
1704 if (typeof setTimeout.clock == "object") {
1705 this.clock = setTimeout.clock;
1706 } else {
1707 this.clock = sinon.useFakeTimers();
1708 this.resetClock = true;
1709 }
1710
1711 if (!this.longestTimeout) {
1712 var clockSetTimeout = this.clock.setTimeout;
1713 var clockSetInterval = this.clock.setInterval;
1714 var server = this;
1715
1716 this.clock.setTimeout = function (fn, timeout) {
1717 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
1718
1719 return clockSetTimeout.apply(this, arguments);
1720 };
1721
1722 this.clock.setInterval = function (fn, timeout) {
1723 server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
1724
1725 return clockSetInterval.apply(this, arguments);
1726 };
1727 }
1728 }
1729
1730 return sinon.fakeServer.addRequest.call(this, xhr);
1731 };
1732
1733 sinon.fakeServerWithClock.respond = function respond() {
1734 var returnVal = sinon.fakeServer.respond.apply(this, arguments);
1735
1736 if (this.clock) {
1737 this.clock.tick(this.longestTimeout || 0);
1738 this.longestTimeout = 0;
1739
1740 if (this.resetClock) {
1741 this.clock.restore();
1742 this.resetClock = false;
1743 }
1744 }
1745
1746 return returnVal;
1747 };
1748
1749 sinon.fakeServerWithClock.restore = function restore() {
1750 if (this.clock) {
1751 this.clock.restore();
1752 }
1753
1754 return sinon.fakeServer.restore.apply(this, arguments);
1755 };
1756 }());
1757
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
19 }, 19 },
20 "dependencies": { 20 "dependencies": {
21 "video.js": "git+https://github.com/dmlap/video-js.git#v4.3.0-10", 21 "video.js": "git+https://github.com/dmlap/video-js.git#v4.3.0-10",
22 "videojs-contrib-media-sources": "git+https://github.com/dmlap/videojs-contrib-media-sources.git#hotfix/misc-fixes" 22 "videojs-contrib-media-sources": "git+https://github.com/dmlap/videojs-contrib-media-sources.git#hotfix/misc-fixes",
23 "sinon": "~1.9.0"
23 } 24 }
24 } 25 }
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 <title>video.js HLS Plugin Test Suite</title> 5 <title>video.js HLS Plugin Test Suite</title>
6 <!-- Load sinon server for fakeXHR --> 6 <!-- Load sinon server for fakeXHR -->
7 <script src="../libs/sinon/sinon-server-1.9.0.js"></script> 7 <script src="../node_modules/sinon/lib/sinon.js"></script>
8 <script src="../node_modules/sinon/lib/sinon/util/event.js"></script>
9 <script src="../node_modules/sinon/lib/sinon/util/xhr_ie.js"></script>
10 <script src="../node_modules/sinon/lib/sinon/util/fake_xml_http_request.js"></script>
8 11
9 <!-- Load local QUnit. --> 12 <!-- Load local QUnit. -->
10 <link rel="stylesheet" href="../libs/qunit/qunit.css" media="screen"> 13 <link rel="stylesheet" href="../libs/qunit/qunit.css" media="screen">
......