Sinon.js-JavaScript用のモックライブラリ

Sinon.jsは、任意のテストフレームワークで使用できるJavaScriptモックライブラリです。 JavaScriptで必要な動作をエミュレートおよび検証するための機能を提供します。 このライブラリは、スパイ、スタブ、およびモックを使用した3種類のテストを提供します。 この投稿では、Sinon.js APIドキュメントと、このライブラリのメソッドの概念を簡単に紹介します。







スパイ



Spyは、すべての呼び出しで生成された引数、戻り値、初期値、およびエラー(ある場合)を記録する関数です。 テストスパイは、匿名関数にすることも、既存の関数の上に作成することもできます。



テストスパイは、コールバックと、テスト中にシステム全体で特定の関数/メソッドがどのように使用されるかを確認するのに役立ちます。 次の簡単な例は、スパイウェアを使用してコールバック関数の処理をテストする方法を示しています。



"test should call subscribers on publish": function () { var callback = sinon.spy(); PubSub.subscribe("message", callback); PubSub.publishSync("message"); assertTrue(callback.called); }
      
      







Sinon.spyは、既存の機能を追跡することもできます。 実行されると、元の関数は通常どおりに動作しますが、すべての呼び出しに関するデータにアクセスできます。 以下は、少し抽象的な例です。



 { setUp: function () { sinon.spy(jQuery, "ajax"); }, tearDown: function () { jQuery.ajax.restore(); // Unwraps the spy }, "test should inspect jQuery.getJSON's usage of jQuery.ajax": function () { jQuery.getJSON("/some/resource"); assert(jQuery.ajax.calledOnce); assertEquals("/some/resource", jQuery.ajax.getCall(0).args[0].url); assertEquals("json", jQuery.ajax.getCall(0).args[0].dataType); } }
      
      





スパイの作成:sinon.spy()



var spy = sinon.spy();





すべての呼び出しに対して、現在の値に引数を、エラーメッセージに、引数を戻り値に書き込む匿名関数を定義します。

var spy = sinon.spy(myFunc);





完成した関数の上にスパイを作成します。

var spy = sinon.spy(object, "method");





object.method



スパイを作成し、元のメソッドを置き換えます。 すべての場合において、元のバージョンとまったく同じように機能します。 元のメソッドは、 object.method.restore ()



を使用して復元できます。



スパイAPI



Spyは、その使用を制御するための幅広いインターフェースを提供します。 上記の例は、 calledOnce



という論理プロパティ、およびgetCall



メソッドと返されたオブジェクトへの引数を示しています。 通話データを確認するには、3つの方法があります。



最も望ましいアプローチは、 calledWith



メソッドを使用することです。これにより、不必要な詳細からテストを保存できます。 関数呼び出しが実行された回数を常に知る必要はありません。戻り値のデータで十分な場合もあります。



 "test should call subscribers with message as first argument" : function () { var message = 'an example message'; var spy = sinon.spy(); PubSub.subscribe(message, spy); PubSub.publishSync(message, "some payload"); assert(spy.calledWith(message)); }
      
      





さらに詳細が必要な場合は、最初の呼び出しの最初のパラメーターを直接確認できます。 これを行うには、次の方法が役立ちます。



 "test should call subscribers with message as first argument" : function () { var message = 'an example message'; var spy = sinon.spy(); PubSub.subscribe(message, spy); PubSub.publishSync(message, "some payload"); assertEquals(message, spy.args[0][0]); }
      
      







 "test should call subscribers with message as first argument" : function () { var message = 'an example message'; var spy = sinon.spy(); PubSub.subscribe(message, spy); PubSub.publishSync(message, "some payload"); assertEquals(message, spy.getCall(0).args[0]); }
      
      







最初の例では、スパイ上で直接引数の2次元配列を使用しますが、2番目の例では、呼び出しの最初の値を選択して、その引数にアクセスします。 どちらを使用するかは好みの問題ですが、テストをさらに詳細に行う必要がない場合は、 spy.calledWith (arg1, arg2...)



アプローチを使用することをお勧めします。



スパイAPI
スパイオブジェクトまたはsinon.spy()



から返されたオブジェクト。 sinon.spy (object, method)



で既存のメソッドを追跡する場合、次のプロパティとメソッドもobject.method



で使用できます。



spy.withArgs(arg1[, arg2, ...]);





受け取った引数がwithArgs



渡された引数と一致する場合にのみ呼び出しを記録するスパイを作成します。



 "should call method once with each argument": function () { var object = { method: function () {} }; var spy = sinon.spy(object, "method"); spy.withArgs(42); spy.withArgs(1); object.method(42); object.method(1); assert(spy.withArgs(42).calledOnce); assert(spy.withArgs(1).calledOnce); }
      
      





spy.callCount





登録されたコールの数を表示します。

spy.called





スパイが少なくとも1回呼び出された場合に確認を提供します。

spy.calledOnce





スパイが一度だけ呼び出された場合に確認を提供します。

spy.calledTwice





スパイが2回だけ呼び出された場合に確認を提供します。

spy.calledThrice





スパイが3回だけ呼び出された場合に確認を提供します。

spy.firstCall





最初の挑戦。

spy.secondCall





2番目の課題。

spy.thirdCall





3番目の課題。

spy.lastCall





最後の呼び出し。

spy.calledBefore(anotherSpy);





anotherSpy



前にスパイが呼び出された場合、確認を返します。

spy.calledAfter(anotherSpy);





スパイがanotherSpy



後に呼び出された場合、確認を返します。

spy.calledOn(obj);





このようなobjでスパイが少なくとも1回呼び出された場合、確認を返します。

spy.alwaysCalledOn(obj);





スパイが常にこのようにobjで呼び出されている場合、確認を返します。

spy.calledWith(arg1, arg2, ...);





指定された引数でスパイが少なくとも1回呼び出された場合に確認を返します。 部分一致でも実行でき、Sinonは指定された引数のみを実際の引数と照合し、指定された引数と一致する(同じ場所で)確認を得ます。

spy.alwaysCalledWith(arg1, arg2, ...);





スパイが常に提供された引数で(および部分的に他の引数とともに)呼び出される場合、確認を返します。

spy.alwaysCalledWithExactly(arg1, arg2, ...);





指定された引数に従ってスパイが常に完全に呼び出される場合、確認を発行します。

spy.calledWithMatch(arg1, arg2, ...);





スパイが常に提供された引数で(および部分的に他の引数とともに)呼び出される場合、確認を返します。 これは、 spy.calledWith(sinon.match(arg1), sinon.match(arg2), ...)



まったく同じように動作しspy.calledWith(sinon.match(arg1), sinon.match(arg2), ...)





spy.alwaysCalledWithMatch(arg1, arg2, ...);





指定された引数でスパイが常に呼び出される場合、確認を返します。 これは、 spy.alwaysCalledWith(sinon.match(arg1), sinon.match(arg2), ...)



まったく同じように動作しspy.alwaysCalledWith(sinon.match(arg1), sinon.match(arg2), ...)





spy.calledWithNew();





スパイ/スタブが新しい​​ステートメントによって呼び出された場合、確認を返します。 これは、このオブジェクトの値とspy関数のプロトタイプに基づいた結果であり、オブジェクトの正しいビューを積極的に返すと、偽陽性の結果になる可能性があることに注意してください。

spy.neverCalledWith(arg1, arg2, ...);





スパイ/スタブが提供された引数で呼び出されたことがない場合、確認を返します。

spy.neverCalledWithMatch(arg1, arg2, ...);





引数によって提供された大きな値でスパイ/スタブが呼び出されたことがない場合、確認を返します。 これは、 spy.neverCalledWith(sinon.match(arg1), sinon.match(arg2), ...).



まったく同じように動作しspy.neverCalledWith(sinon.match(arg1), sinon.match(arg2), ...).





spy.threw();





スパイが少なくとも1回例外をスローした場合、確認を返します。

spy.threw("TypeError");





スパイが指定されたタイプの例外を少なくとも1回スローした場合、確認を返します。

spy.threw(obj);





スパイが指定されたオブジェクトに対して少なくとも1回例外をスローした場合、確認を返します。

spy.alwaysThrew();





スパイが常に例外をスローする場合、確認をスローします。

spy.alwaysThrew("TypeError");





スパイが常に指定されたタイプの例外をスローした場合、確認を返します。

spy.alwaysThrew(obj);





スパイが常に指定されたオブジェクトの例外をスローした場合、確認を返します。

spy.returned(obj);





スパイが意図した値を少なくとも1回返した場合、確認を発行します。 オブジェクトと配列の詳細な比較を使用します。 厳密な比較には、spy.returned(sinon.match.same(obj))を使用します。

spy.alwaysReturned(obj);





スパイが常に意図した値を返す場合、確認を返します。

var spyCall = spy.getCall(n);





n番目の[呼び出し](#spycall)を返します。 個々の呼び出しへのアクセスを提供し、スパイが複数回呼び出された場合の動作をより詳細に検証するのに役立ちます。 例:



 sinon.spy(jQuery, "ajax"); jQuery.ajax("/stuffs"); var spyCall = jQuery.ajax.getCall(0); assertEquals("/stuffs", spyCall.args[0]);
      
      





spy.thisValues





spy.thisValues[0]



オブジェクトのスコープは、最初の呼び出しのオブジェクトを表します。

spy.args





引数配列spy.args [0]



は、最初の呼び出しで受け取った引数を持つ配列です。

spy.exceptions





スローされた例外の配列spy.exceptions[0]



は、最初の呼び出しでスローされた例外を表します。 呼び出しがエラーを返さなかった場合、 .exceptions



フィールドの値は'undefined'



ます。

spy.returnValues





戻り値の配列、 spy.returnValues[0]



-最初の呼び出しの戻り値。 呼び出しが.returnValues



フィールド値を返した場合、 'undefined'



ます。

spy.reset()





スパイ状態をリセットします。

spy.printf(format string", [arg1, arg2, ...])`





次の置換を使用して、送信されたシーケンス形式を返します。

  • #n:スパイ名(デフォルトでは「スパイ」)
  • #s:スパイが言葉で呼ばれた回数(「1回」、「2回」など)
  • #C:連続したスパイコールのリスト。各コールは改行プレフィックスと4つのスペースでマークされます
  • #t:スパイが呼び出された値のコンマ区切りリスト
  • #:printfに渡されるn番目の引数のn形式の値
  • #*:printfに渡される(フォーマットされていないシーケンス)引数のコンマ区切りリスト


個別のスパイコール



var spyCall = spy.getCall(n)





n番目の[call](#spycall)



提供します。 個々の呼び出しにアクセスすると、スパイが何度も呼び出されたときの動作をより詳細に検証できます。 例:



 sinon.spy(jQuery, "ajax"); jQuery.ajax("/stuffs"); var spyCall = jQuery.ajax.getCall(0); assertEquals("/stuffs", spyCall.args[0]);
      
      





spyCall.calledOn(obj);





アイテムがこの呼び出しに関連していたかどうかを確認します。

spyCall.calledWith(arg1, arg2, ...);





呼び出しが提供された引数を受け取った場合に確認を提供します(類似している可能性があります)。

spyCall.calledWithExactly(arg1, arg2, ...);





呼び出しが提供された引数を受信し、他の引数を受信しなかった場合に確認を提供します。

spyCall.calledWithMatch(arg1, arg2, ...);





呼び出しが提供された引数を受け取った場合に確認を提供します(おそらく類似)。 spyCall.calledWith (sinon.match (arg1), sinon.match (arg2)...).



同じように動作しspyCall.calledWith (sinon.match (arg1), sinon.match (arg2)...).





spyCall.notCalledWith(arg1, arg2, ...);





呼び出しが提供された引数を受け取っていない場合に確認を提供します。

spyCall.notCalledWithMatch(arg1, arg2, ...);





呼び出しが提供された引数を受け取っていない場合に確認を提供します。 spyCall.notCalledWith(sinon.match(arg1), sinon.match(arg2), ...).;



まったく同じように動作しspyCall.notCalledWith(sinon.match(arg1), sinon.match(arg2), ...).;





spyCall.threw();





呼び出しが失敗した場合に確認を提供します。

spyCall.threw(TypeError");





呼び出しが意図したタイプのエラーを生成したかどうかを確認します。

spyCall.threw(obj);





呼び出しが目的のオブジェクトに対してエラーを生成したかどうかを確認します。

spyCall.thisValue





これを呼び出します。

spyCall.args





受信した引数の配列。

spyCall.exception





スローされた例外(エラー)(ある場合)。

spyCall.returnValue





戻り値。



スタブ



スタブは、事前にプログラムされた動作を持つ関数です。 これらは、スタブの動作を変更するために使用できるメソッドに加えて、スパイAPIを完全にサポートしています。



スパイと同様に、スタブは匿名にすることも、既存の関数をラップすることもできます。 既存の関数をスタブでラップする場合、元の関数は呼び出されません。



次の場合にスタブを使用します。

  1. テストの動作を制御し、特定の時点でコードにエラーをスローさせます。 例には、処理を検証するための強制エラー報告方法が含まれます。
  2. 特定のメソッドが直接呼び出されないようにする場合(おそらく、 XMLHttpRequest



    などの不要な動作が発生するため)。


次の例は、Morgan Roderickによる別のPubSubJSテストです。これは、呼び出されたときにエラーをスローする匿名スタブを作成する方法を示しています。



 "test should call all subscribers, even if there are exceptions" : function(){ var message = 'an example message'; var error = 'an example error message'; var stub = sinon.stub().throws(); var spy1 = sinon.spy(); var spy2 = sinon.spy(); PubSub.subscribe(message, stub); PubSub.subscribe(message, spy1); PubSub.subscribe(message, spy2); PubSub.publishSync(message, undefined); assert(spy1.called); assert(spy2.called); assert(stub.calledBefore(spy1)); }
      
      





スタブもスパイインターフェースに含まれていることに注意してください。 このテストでは、必要なコールバックがすべて呼び出されたこと、および新しい呼び出しの前にスタブが現在の呼び出しに対してエラーを生成したことを確認します。



連続呼び出しでのスタブ動作の定義


returns



throws



などの特定の動作への複数の呼び出しは、スタブの動作をオーバーライドします。 バージョンSinon 1.8以降では、<codeonCall </ codeメソッドを使用して、連続した呼び出しに対してスタブから異なる応答を取得できます。



Sinonバージョン1.5および1.7では、 yields*



およびcallsArg*



複数の呼び出しは、連続した呼び出し中に動作シリーズを定義するメソッドのファミリーであることに注意してください。



スタブAPI
var stub = sinon.stub();





匿名スタブ関数を作成します。

var stub = sinon.stub(object, "method");





object.method



をスタブ関数に置き換えます。 元の関数は、 object.method.restore ();



呼び出すことで復元できますobject.method.restore ();



またはstub.restore ();



。 プロパティが関数に関連していない場合、エラーがスローされる可能性があります-これは、スタブを使用するときのタイプミスを避けるために行われます。

var stub = sinon.stub(object, "method", func);





スパイラップされたobject.method



func



置き換えます。 一般的に使用されるのはobject.method.restore ();



元のメソッドを復元します。

var stub = sinon.stub(obj);





指定されたオブジェクトのスタブ。 個々のスタブのメソッドは、理解できないオブジェクトまたはすべてのメソッドを制御するオブジェクト(たとえば、ライブラリに応じて)で使用するためのベストプラクティスであることに注意してください。 個々のスタブのメソッドは、オブジェクトの動作をより正確にテストし、オブジェクトのコードの変更中に予期しない動作の影響を受けにくくします。



MyConstructor



スタブオブジェクトを作成するが、コンストラクターを呼び出さない場合は、次のユーティリティ関数を使用します。

 var stub = sinon.createStubInstance(MyConstructor)
      
      





stub.withArgs(arg1[, arg2, ...]);





スタブメソッドは、指定された引数に対して排他的です。 この方法は、同じチャレンジでスパイにアクセスできるステートメントで表現力を高めるのに役立ちます。 また、さまざまなパラメーターに応じて異なる動作をすることができるスタブを作成すると便利です。



 "test should stub method differently based on arguments": function () { var callback = sinon.stub(); callback.withArgs(42).returns(1); callback.withArgs(1).throws("TypeError"); callback(); // No return value, no exception callback(42); // Returns 1 callback(1); // Throws TypeError }
      
      





stub.onCall(n);





Sinon.JS 1.8で追加されました。

n番目の呼び出しでのスタブの動作を定義します。 順次相互作用のテストに役立ちます。



 "test should stub method differently on consecutive calls": function () { var callback = sinon.stub(); callback.onCall(0).returns(1); callback.onCall(1).returns(2); callback.returns(3); callback(); // Returns 1 callback(); // Returns 2 callback(); // All following calls return 3 }
      
      





特定のスタブをより自然に読み取るためにonFirstCall, onSecondCall, onThirdCall



などの方法があります。

`onCall`



は、このセクションの動作を決定するすべてのメソッドと組み合わせることができます。 特に、 'withArgs'



使用できます。



 "test should stub method differently on consecutive calls with certain argument": function () { var callback = sinon.stub(); callback.withArgs(42) .onFirstCall().returns(1) .onSecondCall().returns(2); callback.returns(0); callback(1); // Returns 0 callback(42); // Returns 1 callback(1); // Returns 0 callback(42); // Returns 2 callback(1); // Returns 0 callback(42); // Returns 0 }
      
      





呼び出しが定義されなくなると、引数42のスタブの動作がデフォルトの動作に戻ることに注意してください。

stub.onFirstCall();





stub.onCallのエイリアス(0);

stub.onSecondCall();





stub.onCallのエイリアス(1);

stub.onThirdCall();





stub.onCallのエイリアス(2);

stub.returns(obj);





スタブが指定されたオブジェクトを返すようにします。

stub.returnsArg(index);





スタブが指定されたインデックスを持つ引数を返すようにします。 stub.callsArg (0);



スタブが強制的に主引数を返すようにします。

stub.returnsThis();





スタブはthis



返します。

stub.throws();





スタブに例外(エラー)をスローさせます。

stub.throws("TypeError");





スタブに指定されたタイプのエラーをスローさせます。

stub.throws(obj);





指定されたオブジェクトに対してスタブにエラーをスローさせます。

stub.callsArg(index);





スタブが指定されたインデックスで引数をコールバック関数として呼び出すようにします。 stub.callsArg (0);



スタブがコールバックのように主引数を呼び出すようにします。

stub.callsArgOn(index, context);





stub.callsArg(index);



同じように実行されstub.callsArg(index);



、ただしthis



コンテキストを渡すための追加のパラメーターがあります。

stub.callsArgWith(index, arg1, arg2, ...);





これは、callsArgと同じ方法で実行されますが、コールバック関数に渡す引数を使用します。

stub.callsArgOnWith(index, context, arg1, arg2, ...);





stub.callsArgWith(index, arg1, arg2, ...);



同様に実行されstub.callsArgWith(index, arg1, arg2, ...);



、ただしthis



コンテキストを渡すための追加のパラメーターがあります。

stub.yields([arg1, arg2, ...])





これは、callsArgとほぼ同じように動作します。 スタブは、指定された引数(存在する場合)で受け取った最初のコールバックを呼び出します。 メソッドが複数のコールバックを受け入れる場合、callsArgを使用して、スタブが最初以外のコールバックを呼び出すことができるようにする必要があります。

stub.yieldsOn(context, [arg1, arg2, ...])





stub.yieldsOn(context, [arg1, arg2, ...]);



同様に実行されstub.yieldsOn(context, [arg1, arg2, ...]);



、ただしthis



コンテキストを渡すための追加のパラメーターがあります。

stub.yieldsTo(property, [arg1, arg2, ...])





スパイがオブジェクトプロパティとしてスパイに渡されたコールバックを呼び出すようにします。 yields, yieldsTo



と同様にyields, yieldsTo



は最初に一致する引数を取得し、コールバックを見つけて、(オプションの)引数で呼び出します。

stub.yieldsToOn(property, context, [arg1, arg2, ...])





stub.yieldsTo(property, [arg1, arg2, ...]);



同じように実行されstub.yieldsTo(property, [arg1, arg2, ...]);



、ただしthis



コンテキストを渡すための追加のパラメーターがあります。



 "test should fake successful ajax request": function () { sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]); jQuery.ajax({ success: function (data) { assertEquals([1, 2, 3], data); } }); }
      
      





stub.yield([arg1, arg2, ...])





指定されたパラメーターでスタブに渡されたコールバックを呼び出します。 指定された関数引数でスタブが一度も呼び出されたことがない場合、 yield



はエイリアスinvokeCallback



エラーをinvokeCallback



ます。

stub.yieldTo(callback, [arg1, arg2, ...])





オブジェクトプロパティとしてスパイに渡されるコールバックを呼び出します。 yields, yieldsTo



と同様にyields, yieldsTo



は最初に一致する引数を取得し、コールバックを見つけて、(オプションの)引数で呼び出します。

stub.callArg(argNum)





yield



に似yield



いますが、正確な引数番号を使用して、再度呼び出されるコールバックを定義します。 関数が複数のコールバックで呼び出され、最初のコールバックだけを呼び出す必要がない場合に便利です。



 "calling the last callback": function () { var callback = sinon.stub(); callback(function () { console.log("Success!"); }, function () { console.log("Oh noes!"); }); callback.callArg(1); // Logs "Oh noes!" }
      
      





stub.callArgWith(argNum, [arg1, arg2, ...])





stub.callArg(argNum)



stub.callArg(argNum)



ていますが、引数があります。

stub.callsArgAsync(index);





対応する同期複製と同じことを実行しますが、コールバックが遅延します(すぐに実行されませんが、短いタイムアウトの後、別の「スレッド」で実行されます)。



stub.callsArgAsync(index);





stub.callsArgOnAsync(index, context);





stub.callsArgWithAsync(index, arg1, arg2, ...);





stub.callsArgOnWithAsync(index, context, arg1, arg2, ...);





stub.yieldsAsync([arg1, arg2, ...])





stub.yieldsOnAsync(context, [arg1, arg2, ...])





stub.yieldsToAsync(property, [arg1, arg2, ...])





stub.yieldsToOnAsync(property, context, [arg1, arg2, ...])





それらは対応する同期複製とまったく同じ方法で実行されますが、遅延コールバックを使用します(すぐに実行されますが、短いタイムアウトの後、別の「スレッド」で実行されます)





モック



モックは、(スパイなどの)模倣方法であり、事前にプログラムされた待機と同様に、事前にプログラムされた動作(スタブなど)を備えています。 シミュレーションは、期待どおりに使用されていない場合、テストを実行できません。



シミュレーションは、テストメソッドにのみ使用できます。 各ユニットテストには、テストプロセスで少なくとも1つのブロックが必要です。 このブロックの使用方法を制御し、(事後の主張とは対照的に)予想される結果を設定するには、シミュレーションを使用します。



シミュレーションは、テストから予想される期待値で完了し、テスト全体の失敗につながる可能性があります。 したがって、テストは実行の詳細を課します。 簡単なルールがあります。一部の呼び出しにアサーションを追加しない場合、それらをシミュレートしないでください。 代わりにスタブを使用してください。 いずれの場合でも、1つのテストで複数のシミュレーション(複数の指定された期待値を含む)を使用しないでください。



期待は、スパイAPIとスタブAPIの両方を使用できます。



Sinon.JSでのシミュレーションの様子を見るために、PubSubJSの例を示します。 今回は、コールバックメソッドとその動作をシミュレートする方法を使用します。



 "test should call all subscribers when exceptions": function () { var myAPI = { method: function () {} }; var spy = sinon.spy(); var mock = sinon.mock(myAPI); mock.expects("method").once().throws(); PubSub.subscribe("message", myAPI.method); PubSub.subscribe("message", spy); PubSub.publishSync("message", undefined); mock.verify(); assert(spy.calledOnce); }
      
      





モックAPI
var mock = sinon.mock(obj);





指定されたオブジェクトのシミュレーションを作成します。 オブジェクト自体は変更されませんが、モックオブジェクトをラップして、オブジェクトのメソッドに期待を設定します。

var expectation = mock.expects("method");





obj.method



をシミュレーション関数でオーバーライドして返します。

mock.restore();





すべてのシミュレーション方法を復元します。

mock.verify();





指定されたシミュレーションを検索します。 指定したシミュレーションが検出されなかった場合、エラーメッセージが表示されます。 また、シミュレーション手法の復元にも役立ちます。



期待



すべての期待メソッドは期待を返します。 これは、それらを連結できることを意味します。 典型的な使用法:

 sinon.mock(jQuery).expects("ajax").atLeast(2).atMost(5); jQuery.ajax.verify();
      
      





Expectations API
var expectation = sinon.expectation.create([methodName]);





モック=オブジェクトなしで待機を作成します。基本的には匿名のシミュレーション関数です。 , .

var expectation = sinon.mock();





var expectation = sinon.expectation.create([methodName]);





expectation.atLeast(number);





.

expectation.atMost(number);





.

expectation.never();





, .

expectation.once();





, .

expectation.twice();





, .

expectation.thrice();





, .

expectation.exactly(number);





, .

expectation.withArgs(arg1, arg2, ...);





, ( ).

expectation.withExactArgs(arg1, arg2, ...);





, .

expectation.on(obj);





, obj



this



.

expectation.verify();





, .



偽のタイマー



偽のタイマーはsetTimeoutおよびSinon.JSヘルパーの同期実装であり、グローバル関数を上書きして、それらを使用してコードをより簡単にテストできます。



IEで偽のタイマーを使用するには、sinon-1.17.2.jsをインストールした直後にsinon-ie-1.17.2をインストールする必要があります。



偽のタイマーをオフラインで使用する場合は、lolexパッケージを使用することをお勧めします。これは同じ機能セットを提供し、以前Sinon.JSから抽出されました。



 { setUp: function () { this.clock = sinon.useFakeTimers(); }, tearDown: function () { this.clock.restore(); }, "test should animate element over 500ms" : function(){ var el = jQuery("<div></div>"); el.appendTo(document.body); el.animate({ height: "200px", width: "200px" }); this.clock.tick(510); assertEquals("200px", el.css("height")); assertEquals("200px", el.css("width")); } }
      
      





偽のタイマーAPI
var clock = sinon.useFakeTimers();





Sinon setTimeout, setInterval, clearTimeout, clearInterval



, . UNIX .

var clock = sinon.useFakeTimers(now);





, , (now)



.

var clock = sinon.useFakeTimers([now, ]prop1, prop2, ...);





. — setTimeout, clearTimeout, setInterval



, clearInterval



, . .

clock.tick(ms);





ms



. , .

clock.restore();





. tearDown







偽のXMLHttpRequest



偽の実装XMLHttpRequest



を提供し、それによって作成されたオブジェクトを管理するためのいくつかのインターフェースを提供します。また、自分自身XMLHttpRequest



偽装ActiveXObject



ます。XHRで実行されたクエリのテストを支援します。



IEでXHRを使用するには、sinon-1.17.2.jsをインストールした直後にsinon-ie-1.17.2をインストールする必要があり



ます。sinon -server-1.17.2がロードされていれば、偽サーバーとXHRを完全に自律的に使用できます。IEで偽のサーバーを使用する場合は、sinon-1.17.2も必要です。sinon-server-1.17.2の後にダウンロードします。



 { setUp: function () { this.xhr = sinon.useFakeXMLHttpRequest(); var requests = this.requests = []; this.xhr.onCreate = function (xhr) { requests.push(xhr); }; }, tearDown: function () { this.xhr.restore(); }, "test should fetch comments from server" : function () { var callback = sinon.spy(); myLib.getCommentsFor("/some/article", callback); assertEquals(1, this.requests.length); this.requests[0].respond(200, { "Content-Type": "application/json" }, '[{ "id": 12, "comment": "Hey there" }]'); assert(callback.calledWith([{ id: 12, comment: "Hey there" }])); } }
      
      





sinon.useFakeXMLHttpRequest
var xhr = sinon.useFakeXMLHttpRequest();





Sinon XMLHttpRequest , . , ActiveXObject



, progID XMLHTTP. progID, XMLDOM, .



XMLHttpRequest sinon.xhr. XMLHttpRequest.



xhr.onCreate = function (xhr) {};





onCreate useFakeXMLHttpRequest ()</code. FakeXMLHttpRequest



. API XHR. , jQuery.ajax ( /)

xhr.restore();





().







FakeXMLHttpRequest
String request.url





URL- .

String request.method





.

Object request.requestHeaders





, ..:



 { "Accept": "text/html, */*", "Connection": "keep-alive" }
      
      





String request.requestBody





.

int request.status





. , .

String request.statusText





, .

boolean request.async





.

String request.username





, .

String request.password





, .

Document request.responseXML





, .

String request.getResponseHeader(header);





, .

Object request.getAllResponseHeaders();





.





Sinon.JS / , . FakeXMLHttpRequest



( Sinon 1.3.0) :



方法
FakeXMLHttpRequest.useFilters





. Sinon , .

FakeXMLHttpRequest.addFilter(fn)





, , — . , xhr.open



(, URL, , , ). , .





request.setResponseHeaders(object);





, , { "Content-Type": "text/html", /* ... */ }



, readyState



onreadystatechange



.

request.setResponseBody(body);





, readyState



onreadystatechange



. responseXML



, .

request.respond(status, headers, body);





statusText



. , sinon. FakeXMLHttpRequest.statusCodes



.

Boolean request.autoRespond





, -.- 10 , autoRespondAfter



.



, , .



Number request.autoRespondAfter





, . 10 .



FakeServe



API FakeXMLHttpRequest







 { setUp: function () { this.server = sinon.fakeServer.create(); }, tearDown: function () { this.server.restore(); }, "test should fetch comments from server" : function () { this.server.respondWith("GET", "/some/article/comments.json", [200, { "Content-Type": "application/json" }, '[{ "id": 12, "comment": "Hey there" }]']); var callback = sinon.spy(); myLib.getCommentsFor("/some/article", callback); this.server.respond(); sinon.assert.calledWith(callback, [{ id: 12, comment: "Hey there" }]); } }
      
      





API FakeServe
var server = sinon.fakeServer.create([config]);





. sinon.useFakeXMLHttpRequest ()



. / .

var server = sinon.fakeServerWithClock.create();





, . XHR, , , jQuery 1.3.x onreadystatechange



. jQuery 1.3.x ,

server.configure(config)





. .

server.respondWith(response);





:



  • ,
  • , , , [200, { "Content-Type": "text/html", "Content-Length": 2 }, "OK"]



  • .




200 . [404, {}, ""]







, . , .



server.respondWith(url, response);





URL, , /posts/1





server.respondWith(method, url, response);





URL . — HTTP.

server.respondWith(urlRegExp, response);





URL , , /\/post\//\d+



. XMLHttpRequest



.

 server.respondWith(/\/todo-items\/(\d+)/, function (xhr, id) { xhr.respond(200, { ?Content-Type?: ?application/json? }, ?[{ ?id?: ? + id + ? }]?); });
      
      





server.respondWith(method, urlRegExp, response);





URL-, .

server.respond();





, . respondWith



, [404, {}, ""]



. , , respondWith



. , respondWith



.

server.autoRespond = true;





— -. - 10 , autoRespondAfter



. , . respondImmediately .

server.autoRespondAfter = ms;





-.

server.respondImmediately = true;





, . . , . server.autoRespond server.autoRespondAfter.

Boolean `server.fakeHTTPMethods`





, method



POST . , Ruby Rails. HTTP server.getHTTPMethod.

server.getHTTPMethod(request)





, HTTP, . request.method



. server.fakeHTTPMethods



, _method



, POST. .

server.restore();





XHR .



:



 server.autoRespond = true
      
      





fakeServer.create



.configure



.



boolean autoRespond





-. - 10 , autoRespondAfter



. , , . .

int autoRespondAfter (ms)





-.

boolean respondImmediately





. , . , . server.autoRespond



server.autoRespondAfter



.

boolean fakeHTTPMethods





_method POST . , Ruby Rails. HTTP server.getHTTPMethod



.



JSON-P



JSON-P Ajax, . JSON-P . . — jQuery .



 sinon.stub(jQuery, "ajax"); sinon.assert.calledOnce(jQuery.ajax);
      
      





, , JQuery jQuery.ajax



, JSON-P. .



Assertions



Sinon.JS , . , .



, , sinon.assert.fail



sinon.assert.failException



sinon.assert.expose



sinon.assert.pass



.



, .



 "test should call subscribers with message as first argument" : function () { var message = "an example message"; var spy = sinon.spy(); PubSub.subscribe(message, spy); PubSub.publishSync(message, "some payload"); sinon.assert.calledOnce(spy); sinon.assert.calledWith(spy, message); }
      
      





Assertions API
sinon.assert.fail(message)





, . sinon.assert.failException



. , , .

sinon.assert.failException





.

sinon.assert.pass(assertion)





, . .

sinon.assert.notCalled(spy)





, .

sinon.assert.called(spy)





, .

sinon.assert.calledOnce(spy)





, .

sinon.assert.calledTwice()





, .

sinon.assert.calledThrice()





, .

sinon.assert.callCount(spy, num)





.

sinon.assert.callOrder(spy1, spy2, ...)





, .

sinon.assert.calledOn(spy, obj)





, this.

sinon.assert.alwaysCalledOn(spy, obj)





, this.

sinon.assert.calledWith(spy, arg1, arg2, ...)





, ( ).

sinon.assert.alwaysCalledWith(spy, arg1, arg2, ...)





, ( ).

sinon.assert.neverCalledWith(spy, arg1, arg2, ...)





, .

sinon.assert.calledWithExactly(spy, arg1, arg2, ...)





, .

sinon.assert.alwaysCalledWithExactly(spy, arg1, arg2, ...)





, .

sinon.assert.calledWithMatch(spy, arg1, arg2, ...)





, . sinon.assert.calledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)



.

sinon.assert.alwaysCalledWithMatch(spy, arg1, arg2, ...)





, . sinon.assert.alwaysCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)



.

sinon.assert.neverCalledWithMatch(spy, arg1, arg2, ...)





, . sinon.assert.neverCalledWith(spy, sinon.match(arg1), sinon.match(arg2), ...)



.

sinon.assert.threw(spy, exception)





, (). , , . , .

sinon.assert.alwaysThrew(spy, exception)





, .

sinon.assert.expose(object, options)





. , JsTestDriver , Sinon.JS :

 sinon.assert.expose(this);
      
      





assertCalled(spy),assertCallOrder(spy1, spy2, ...) ..



. Prefix — , . assert



, sinon.assert.called



target.assertCalled



. , target.called



. , includeFail



failException



.



Matchers



spy.calledWith



, spy.returned



sinon.assert



spy.withArgs



.

, .



 "test should assert fuzzy": function () { var book = { pages: 42, author: "cjno" }; var spy = sinon.spy(); spy(book); sinon.assert.calledWith(spy, sinon.match({ author: "cjno" })); sinon.assert.calledWith(spy, sinon.match.has("pages", 42)); }
      
      





 "test should stub method differently based on argument types": function () { var callback = sinon.stub(); callback.withArgs(sinon.match.string).returns(true); callback.withArgs(sinon.match.number).throws("TypeError"); callback("abc"); // Returns true callback(123); // Throws TypeError }
      
      





Matchers API
sinon.match(number)





, .

sinon.match(string)





, .

sinon.match(regexp)





, .

sinon.match(object)





, . .

sinon.match(function)





.

sinon.match.any





.

sinon.match.defined





, .

sinon.match.truthy





, .

sinon.match.falsy





, .

sinon.match.bool





, .

sinon.match.number





, .

sinon.match.string





.

sinon.match.object





.

sinon.match.func





, .

sinon.match.array





, .

sinon.match.regexp





, .

sinon.match.date





, .

sinon.match.same(ref)





, ref





sinon.match.typeOf(type)





, , undefined



, null



, boolean



, number



, string



, object



, function



, array



, regexp



date



.

sinon.match.instanceOf(type)





, .

sinon.match.has(property[, expectation])





, . .

sinon.match.hasOwn(property[, expectation])





sinon.match.has, . .





«» «». . , () () .



 var stringOrNumber = sinon.match.string.or(sinon.match.number); var bookWithPages = sinon.match.instanceOf(Book).and(sinon.match.has("pages"));
      
      







sinon.match



, . , true



, 'false' — . , , .



 var trueIsh = sinon.match(function (value) { return !!value; }, "trueIsh");
      
      





Sandboxes



, / . , XHR, / , , .



 "test using sinon.test sandbox": sinon.test(function () { var myAPI = { method: function () {} }; this.mock(myAPI).expects("method").once(); PubSub.subscribe("message", myAPI.method); PubSub.publishSync("message", undefined); })
      
      





Sandbox API
var sandbox = sinon.sandbox.create();





sandbox.

var sandbox = sinon.sandbox.create(config);





'sinon.sandbox.create (config)' — , Sinon.JS , , .



sandbox. sandbox , , . :



 sinon.defaultConfig = { // ... injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }
      
      





  • injectInto





    sandbox . «injectInto» . `sinon.test` , ` this` .
  • properties





    . , «server» . '', , 'useFakeServer' .
  • useFakeTimers





    'true', sandbox ''. .
  • useFakeServer





    `true`, `server` `requests` sandbox. . — 'sinon.fakeServer', jQuery 1.3.x , 'onreadystatechange' XHR , :



     sinon.config = { useFakeServer: sinon.fakeServerWithClock };
          
          







sandbox.spy();





sinon.spy



, sandbox.restore ()



.

sandbox.stub();





sinon.stub



, sandbox.restore ()



. sandbox stub



, . , , .

sandbox.mock();





sinon.mock



, sandbox.restore ()



.

sandbox.useFakeTimers();





sandbox, , sandbox.restore (). sandbox.clock.

sandbox.useFakeXMLHttpRequest();





XHR sandbox



, , sandbox.restore ()



. sandbox.requests



.

sandbox.useFakeServer();





XHR sandbox



, , sandbox.restore ()



. sandbox.requests



sandbox.server



.

sandbox.restore();





sandbox.





sinon.test



Sinon.JS sandbox



. sinon.config



.

var wrappedFn = sinon.test(fn);







wrappedFn



. , sandbox , . spy



, stub



mock



sandbox , , this.spy () (stub mock)



, sandbox.spy () (stub mock)



, .



 { injectIntoThis: true, injectInto: null, properties: ["spy", "stub", "mock", "clock", "server", "requests"], useFakeTimers: true, useFakeServer: true }
      
      





sinon.config



, , :



 sinon.config = { useFakeTimers: false, useFakeServer: false }
      
      





. , sandbox .

sinon.config


Sinon sinon.test



. :



Boolean injectIntoThis





, . .

Object injectInto





, . null



( ) injectIntoThis



false



( ), .

Array properties





. — : [spy, stub, mock, clock, server, requests]



. , — .

Boolean useFakeTimers





, . .

Boolean useFakeServer





XHR , . — .





sinon.test



, sinon.testCase



, , sinon.test



:` setUp



tearDown



.



var obj = sinon.testCase({});







Sinon.JS



Sinon.JS , . , API.



API
sinon.createStubInstance(constructor)





, . . API .

sinon.format(object)





. .

sinon.log(string)





, .



, .



ソースコード
(function (root, factory) {

'use strict';

if (typeof define === 'function' && define.amd) {

define('sinon', [], function () {

return (root.sinon = factory());

});

} else if (typeof exports === 'object') {

module.exports = factory();

} else {

root.sinon = factory();

}

}(this, function () {

'use strict';

var samsam, formatio, lolex;

(function () {

function define(mod, deps, fn) {

if (mod == «samsam») {

samsam = deps();

} else if (typeof deps === «function» && mod.length === 0) {

lolex = deps();

} else if (typeof fn === «function») {

formatio = fn(samsam);

}

}

define.amd = {};

((typeof define === «function» && define.amd && function (m) { define(«samsam», m); }) ||

(typeof module === «object» &&

function (m) { module.exports = m(); }) || // Node

function (m) { this.samsam = m(); } // Browser globals

)(function () {

var o = Object.prototype;

var div = typeof document !== «undefined» && document.createElement(«div»);



function isNaN(value) {

// Unlike global isNaN, this avoids type coercion

// typeof check avoids IE host object issues, hat tip to

// lodash

var val = value; // JsLint thinks value !== value is «weird»

return typeof value === «number» && value !== val;

}



function getClass(value) {

// Returns the internal [[Class]] by calling Object.prototype.toString

// with the provided value as this. Return value is a string, naming the

// internal class, eg «Array»

return o.toString.call(value).split(/[ \]]/)[1];

}



/**

* name samsam.isArguments

* param Object object

*

* Returns ``true`` if ``object`` is an ``arguments`` object,

* ``false`` otherwise.

* /

function isArguments(object) {

if (getClass(object) === 'Arguments') { return true; }

if (typeof object !== «object» || typeof object.length !== «number» ||

getClass(object) === «Array») {

falseを返します。

}

if (typeof object.callee == «function») { return true; }

{

object[object.length] = 6;

delete object[object.length];

} catch (e) {

return true;

}

falseを返します。

}



/**

* name samsam.isElement

* param Object object

*

* Returns ``true`` if ``object`` is a DOM element node. Unlike

* Underscore.js/lodash, this function will return ``false`` if ``object``

* is an *element-like* object, ie a regular object with a ``nodeType``

* property that holds the value ``1``.

* /

function isElement(object) {

if (!object || object.nodeType !== 1 || !div) { return false; }

{

object.appendChild(div);

object.removeChild(div);

} catch (e) {

falseを返します。

}

return true;

}



/**

* name samsam.keys

* param Object object

*

* Return an array of own property names.

* /

function keys(object) {

var ks = [], prop;

for (prop in object) {

if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }

}

return ks;

}



/**

* name samsam.isDate

* param Object value

*

* Returns true if the object is a ``Date``, or *date-like*. Duck typing

* of date objects work by checking that the object has a ``getTime``

* function whose return value equals the return value from the object's

* ``valueOf``.

* /

function isDate(value) {

return typeof value.getTime == «function» &&

value.getTime() == value.valueOf();

}



/**

* name samsam.isNegZero

* param Object value

*

* Returns ``true`` if ``value`` is ``-0``.

* /

function isNegZero(value) {

return value === 0 && 1 / value === -Infinity;

}



/**

* name samsam.equal

* param Object obj1

* param Object obj2

*

* Returns ``true`` if two objects are strictly equal. Compared to

* ``===`` there are two exceptions:

*

* — NaN is considered equal to NaN

* — -0 and +0 are not considered equal

* /

function identical(obj1, obj2) {

if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {

return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);

}

}



/**

* name samsam.deepEqual

* param Object obj1

* param Object obj2

*

* Deep equal comparison. Two values are «deep equal» if:

*

* — They are equal, according to samsam.identical

* — They are both date objects representing the same time

* — They are both arrays containing elements that are all deepEqual

* — They are objects with the same set of properties, and each property

* in ``obj1`` is deepEqual to the corresponding property in ``obj2``

*

* Supports cyclic objects.

* /

function deepEqualCyclic(obj1, obj2) {



// used for cyclic comparison

// contain already visited objects

var objects1 = [],

objects2 = [],

// contain pathes (position in the object structure)

// of the already visited objects

// indexes same as in objects arrays

paths1 = [],

paths2 = [],

// contains combinations of already compared objects

// in the manner: { "$1['ref']$2['ref']": true }

compared = {};



/**

* used to check, if the value of a property is an object

* (cyclic logic is only needed for objects)

* only needed for cyclic logic

* /

function isObject(value) {



if (typeof value === 'object' && value !== null &&

!(value instanceof Boolean) &&

!(value instanceof Date) &&

!(value instanceof Number) &&

!(value instanceof RegExp) &&

!(value instanceof String)) {



return true;

}



falseを返します。

}



/**

* returns the index of the given object in the

* given objects array, -1 if not contained

* only needed for cyclic logic

* /

function getIndex(objects, obj) {



var i;

for (i = 0; i < objects.length; i++) {

if (objects[i] === obj) {

return i;

}

}



return -1;

}



// does the recursion for the deep equal check

return (function deepEqual(obj1, obj2, path1, path2) {

var type1 = typeof obj1;

var type2 = typeof obj2;



// == null also matches undefined

if (obj1 === obj2 ||

isNaN(obj1) || isNaN(obj2) ||

obj1 == null || obj2 == null ||

type1 !== «object» || type2 !== «object») {



return identical(obj1, obj2);

}



// Elements are only equal if identical(expected, actual)

if (isElement(obj1) || isElement(obj2)) { return false; }



var isDate1 = isDate(obj1), isDate2 = isDate(obj2);

if (isDate1 || isDate2) {

if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {

falseを返します。

}

}



if (obj1 instanceof RegExp && obj2 instanceof RegExp) {

if (obj1.toString() !== obj2.toString()) { return false; }

}



var class1 = getClass(obj1);

var class2 = getClass(obj2);

var keys1 = keys(obj1);

var keys2 = keys(obj2);



if (isArguments(obj1) || isArguments(obj2)) {

if (obj1.length !== obj2.length) { return false; }

} else {

if (type1 !== type2 || class1 !== class2 ||

keys1.length !== keys2.length) {

falseを返します。

}

}



var key, i, l,

// following vars are used for the cyclic logic

value1, value2,

isObject1, isObject2,

index1, index2,

newPath1, newPath2;



for (i = 0, l = keys1.length; i < l; i++) {

key = keys1[i];

if (!o.hasOwnProperty.call(obj2, key)) {

falseを返します。

}



// Start of the cyclic logic



value1 = obj1[key];

value2 = obj2[key];



isObject1 = isObject(value1);

isObject2 = isObject(value2);



// determine, if the objects were already visited

// (it's faster to check for isObject first, than to

// get -1 from getIndex for non objects)

index1 = isObject1? getIndex(objects1, value1): -1;

index2 = isObject2? getIndex(objects2, value2): -1;



// determine the new pathes of the objects

// — for non cyclic objects the current path will be extended

// by current property name

// — for cyclic objects the stored path is taken

newPath1 = index1 !== -1

? paths1[index1]

: path1 + '[' + JSON.stringify(key) + ']';

newPath2 = index2 !== -1

? paths2[index2]

: path2 + '[' + JSON.stringify(key) + ']';



// stop recursion if current objects are already compared

if (compared[newPath1 + newPath2]) {

return true;

}



// remember the current objects and their pathes

if (index1 === -1 && isObject1) {

objects1.push(value1);

paths1.push(newPath1);

}

if (index2 === -1 && isObject2) {

objects2.push(value2);

paths2.push(newPath2);

}



// remember that the current objects are already compared

if (isObject1 && isObject2) {

compared[newPath1 + newPath2] = true;

}



// End of cyclic logic



// neither value1 nor value2 is a cycle

// continue with next level

if (!deepEqual(value1, value2, newPath1, newPath2)) {

falseを返します。

}

}



return true;



}(obj1, obj2, '$1', '$2'));

}



var match;



function arrayContains(array, subset) {

if (subset.length === 0) { return true; }

var i, l, j, k;

for (i = 0, l = array.length; i < l; ++i) {

if (match(array[i], subset[0])) {

for (j = 0, k = subset.length; j < k; ++j) {

if (!match(array[i + j], subset[j])) { return false; }

}

return true;

}

}

falseを返します。

}



/**

* name samsam.match

* param Object object

* param Object matcher

*

* Compare arbitrary value ``object`` with matcher.

* /

match = function match(object, matcher) {

if (matcher && typeof matcher.test === «function») {

return matcher.test(object);

}



if (typeof matcher === «function») {

return matcher(object) === true;

}



if (typeof matcher === «string») {

matcher = matcher.toLowerCase();

var notNull = typeof object === «string» || !!object;

return notNull &&

(String(object)).toLowerCase().indexOf(matcher) >= 0;

}



if (typeof matcher === «number») {

return matcher === object;

}



if (typeof matcher === «boolean») {

return matcher === object;

}



if (typeof(matcher) === «undefined») {

return typeof(object) === «undefined»;

}



if (matcher === null) {

return object === null;

}



if (getClass(object) === «Array» && getClass(matcher) === «Array») {

return arrayContains(object, matcher);

}



if (matcher && typeof matcher === «object») {

if (matcher === object) {

return true;

}

var prop;

for (prop in matcher) {

var value = object[prop];

if (typeof value === «undefined» &&

typeof object.getAttribute === «function») {

value = object.getAttribute(prop);

}

if (matcher[prop] === null || typeof matcher[prop] === 'undefined') {

if (value !== matcher[prop]) {

falseを返します。

}

} else if (typeof value === «undefined» || !match(value, matcher[prop])) {

falseを返します。

}

}

return true;

}



throw new Error(«Matcher was not a string, a number, a » +

«function, a boolean or an object»);

};



return {

isArguments: isArguments,

isElement: isElement,

isDate: isDate,

isNegZero: isNegZero,

identical: identical,

deepEqual: deepEqualCyclic,

match: match,

keys: keys

};

});

((typeof define === «function» && define.amd && function (m) {

define(«formatio», [«samsam»], m);

}) || (typeof module === «object» && function (m) {

module.exports = m(require(«samsam»));

}) || function (m) { this.formatio = m(this.samsam); }

)(function (samsam) {



var formatio = {

excludeConstructors: [«Object», /^.$/],

quoteStrings: true,

limitChildrenCount: 0

};



var hasOwn = Object.prototype.hasOwnProperty;



var specialObjects = [];

if (typeof global !== «undefined») {

specialObjects.push({ object: global, value: "[object global]" });

}

if (typeof document !== «undefined») {

specialObjects.push({

object: document,

value: "[object HTMLDocument]"

});

}

if (typeof window !== «undefined») {

specialObjects.push({ object: window, value: "[object Window]" });

}



function functionName(func) {

if (!func) { return ""; }

if (func.displayName) { return func.displayName; }

if (func.name) { return func.name; }

var matches = func.toString().match(/function\s+([^\(]+)/m);

return (matches && matches[1]) || "";

}



function constructorName(f, object) {

var name = functionName(object && object.constructor);

var excludes = f.excludeConstructors ||

formatio.excludeConstructors || [];



var i, l;

for (i = 0, l = excludes.length; i < l; ++i) {

if (typeof excludes[i] === «string» && excludes[i] === name) {

return "";

} else if (excludes[i].test && excludes[i].test(name)) {

return "";

}

}



return name;

}



function isCircular(object, objects) {

if (typeof object !== «object») { return false; }

var i, l;

for (i = 0, l = objects.length; i < l; ++i) {

if (objects[i] === object) { return true; }

}

falseを返します。

}



function ascii(f, object, processed, indent) {

if (typeof object === «string») {

var qs = f.quoteStrings;

var quote = typeof qs !== «boolean» || qs;

return processed || quote? '"' + object + '"': object;

}



if (typeof object === «function» && !(object instanceof RegExp)) {

return ascii.func(object);

}



processed = processed || [];



if (isCircular(object, processed)) { return "[Circular]"; }



if (Object.prototype.toString.call(object) === "[object Array]") {

return ascii.array.call(f, object, processed);

}



if (!object) { return String((1/object) === -Infinity? "-0": object); }

if (samsam.isElement(object)) { return ascii.element(object); }



if (typeof object.toString === «function» &&

object.toString !== Object.prototype.toString) {

return object.toString();

}



var i, l;

for (i = 0, l = specialObjects.length; i < l; i++) {

if (object === specialObjects[i].object) {

return specialObjects[i].value;

}

}



return ascii.object.call(f, object, processed, indent);

}



ascii.func = function (func) {

return «function » + functionName(func) + "() {}";

};



ascii.array = function (array, processed) {

processed = processed || [];

processed.push(array);

var pieces = [];

var i, l;

l = (this.limitChildrenCount > 0)?

Math.min(this.limitChildrenCount, array.length): array.length;



for (i = 0; i < l; ++i) {

pieces.push(ascii(this, array[i], processed));

}



if(l < array.length)

pieces.push("[… " + (array.length — l) + " more elements]");



return "[" + pieces.join(", ") + "]";

};



ascii.object = function (object, processed, indent) {

processed = processed || [];

processed.push(object);

indent = indent || 0;

var pieces = [], properties = samsam.keys(object).sort();

var length = 3;

var prop, str, obj, i, k, l;

l = (this.limitChildrenCount > 0)?

Math.min(this.limitChildrenCount, properties.length): properties.length;



for (i = 0; i < l; ++i) {

prop = properties[i];

obj = object[prop];



if (isCircular(obj, processed)) {

str = "[Circular]";

} else {

str = ascii(this, obj, processed, indent + 2);

}



str = (/\s/.test(prop)? '"' + prop + '"': prop) + ": " + str;

length += str.length;

pieces.push(str);

}



var cons = constructorName(this, object);

var prefix = cons? "[" + cons + "] ": "";

var is = "";

for (i = 0, k = indent; i < k; ++i) { is += " "; }



if(l < properties.length)

pieces.push("[… " + (properties.length — l) + " more elements]");



if (length + indent > 80) {

return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +

is + "}";

}

return prefix + "{ " + pieces.join(", ") + " }";

};



ascii.element = function (element) {

var tagName = element.tagName.toLowerCase();

var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;



for (i = 0, l = attrs.length; i < l; ++i) {

attr = attrs.item(i);

attrName = attr.nodeName.toLowerCase().replace(«html:», "");

val = attr.nodeValue;

if (attrName !== «contenteditable» || val !== «inherit») {

if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }

}

}



var formatted = "<" + tagName + (pairs.length > 0? " ": "");

var content = element.innerHTML;



if (content.length > 20) {

content = content.substr(0, 20) + "[...]";

}



var res = formatted + pairs.join(" ") + ">" + content +

"</" + tagName + ">";



return res.replace(/ contentEditable=«inherit»/, "");

};



function Formatio(options) {

for (var opt in options) {

this[opt] = options[opt];

}

}



Formatio.prototype = {

functionName: functionName,



configure: function (options) {

return new Formatio(options);

}、



constructorName: function (object) {

return constructorName(this, object);

}、



ascii: function (object, processed, indent) {

return ascii(this, object, processed, indent);

}

};



return Formatio.prototype;

});

!function(e){if(«object»==typeof exports&&«undefined»!=typeof module)module.exports=e();else if(«function»==typeof define&&define.amd)define([],e);else{var f;«undefined»!=typeof window?f=window:«undefined»!=typeof global?f=global:«undefined»!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==«function»&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(«Cannot find module '»+o+"'");throw f.code=«MODULE_NOT_FOUND»,f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==«function»&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){

(function (global){

/*global global, window*/

/**

* author Christian Johansen (christian@cjohansen.no) and contributors

* @license BSD

*

* Copyright © 2010-2014 Christian Johansen

* /



(function (global) {



// Make properties writable in IE, as per

// www.adequatelygood.com/Replacing-setTimeout-Globally.html

// JSLint being anal

var glbl = global;



global.setTimeout = glbl.setTimeout;

global.clearTimeout = glbl.clearTimeout;

global.setInterval = glbl.setInterval;

global.clearInterval = glbl.clearInterval;

global.Date = glbl.Date;



// setImmediate is not a standard function

// avoid adding the prop to the window object if not present

if('setImmediate' in global) {

global.setImmediate = glbl.setImmediate;

global.clearImmediate = glbl.clearImmediate;

}



// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()

// browsers, a number.

// see github.com/cjohansen/Sinon.JS/pull/436



var NOOP = function () { return undefined; };

var timeoutResult = setTimeout(NOOP, 0);

var addTimerReturnsObject = typeof timeoutResult === «object»;

clearTimeout(timeoutResult);



var NativeDate = Date;

var uniqueTimerId = 1;



/**

* Parse strings like «01:10:00» (meaning 1 hour, 10 minutes, 0 seconds) into

* number of milliseconds. This is used to support human-readable strings passed

* to clock.tick()

* /

function parseTime(str) {

if (!str) {

0を返します。

}



var strings = str.split(":");

var l = strings.length, i = l;

var ms = 0, parsed;



if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {

throw new Error(«tick only understands numbers and 'h:m:s'»);

}



while (i--) {

parsed = parseInt(strings[i], 10);



if (parsed >= 60) {

throw new Error(«Invalid time » + str);

}



ms += parsed * Math.pow(60, (l — i — 1));

}



return ms * 1000;

}



/**

* Used to grok the `now` parameter to createClock.

* /

function getEpoch(epoch) {

if (!epoch) { return 0; }

if (typeof epoch.getTime === «function») { return epoch.getTime(); }

if (typeof epoch === «number») { return epoch; }

throw new TypeError(«now should be milliseconds since UNIX epoch»);

}



function inRange(from, to, timer) {

return timer && timer.callAt >= from && timer.callAt <= to;

}



function mirrorDateProperties(target, source) {

var prop;

for (prop in source) {

if (source.hasOwnProperty(prop)) {

target[prop] = source[prop];

}

}



// set special now implementation

if (source.now) {

target.now = function now() {

return target.clock.now;

};

} else {

delete target.now;

}



// set special toSource implementation

if (source.toSource) {

target.toSource = function toSource() {

return source.toSource();

};

} else {

delete target.toSource;

}



// set special toString implementation

target.toString = function toString() {

return source.toString();

};



target.prototype = source.prototype;

target.parse = source.parse;

target.UTC = source.UTC;

target.prototype.toUTCString = source.prototype.toUTCString;



return target;

}



function createDate() {

function ClockDate(year, month, date, hour, minute, second, ms) {

// Defensive and verbose to avoid potential harm in passing

// explicit undefined when user does not pass argument

switch (arguments.length) {

case 0:

return new NativeDate(ClockDate.clock.now);

ケース1:

return new NativeDate(year);

ケース2:

return new NativeDate(year, month);

ケース3:

return new NativeDate(year, month, date);

ケース4:

return new NativeDate(year, month, date, hour);

ケース5:

return new NativeDate(year, month, date, hour, minute);

ケース6:

return new NativeDate(year, month, date, hour, minute, second);

デフォルト:

return new NativeDate(year, month, date, hour, minute, second, ms);

}

}



return mirrorDateProperties(ClockDate, NativeDate);

}



function addTimer(clock, timer) {

if (timer.func === undefined) {

throw new Error(«Callback must be provided to timer calls»);

}



if (!clock.timers) {

clock.timers = {};

}



timer.id = uniqueTimerId++;

timer.createdAt = clock.now;

timer.callAt = clock.now + (timer.delay || (clock.duringTick? 1: 0));



clock.timers[timer.id] = timer;



if (addTimerReturnsObject) {

return {

id: timer.id,

ref: NOOP,

unref: NOOP

};

}



return timer.id;

}



function compareTimers(a, b) {

// Sort first by absolute timing

if (a.callAt < b.callAt) {

return -1;

}

if (a.callAt > b.callAt) {

return 1;

}



// Sort next by immediate, immediate timers take precedence

if (a.immediate && !b.immediate) {

return -1;

}

if (!a.immediate && b.immediate) {

return 1;

}



// Sort next by creation time, earlier-created timers take precedence

if (a.createdAt < b.createdAt) {

return -1;

}

if (a.createdAt > b.createdAt) {

return 1;

}



// Sort next by id, lower-id timers take precedence

if (a.id < b.id) {

return -1;

}

if (a.id > b.id) {

return 1;

}



// As timer ids are unique, no fallback `0` is necessary

}



function firstTimerInRange(clock, from, to) {

var timers = clock.timers,

timer = null,

id,

isInRange;



for (id in timers) {

if (timers.hasOwnProperty(id)) {

isInRange = inRange(from, to, timers[id]);



if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) {

timer = timers[id];

}

}

}



return timer;

}



function callTimer(clock, timer) {

var exception;



if (typeof timer.interval === «number») {

clock.timers[timer.id].callAt += timer.interval;

} else {

delete clock.timers[timer.id];

}



{

if (typeof timer.func === «function») {

timer.func.apply(null, timer.args);

} else {

eval(timer.func);

}

} catch (e) {

exception = e;

}



if (!clock.timers[timer.id]) {

if (exception) {

throw exception;

}

帰る

}



if (exception) {

throw exception;

}

}



function timerType(timer) {

if (timer.immediate) {

return «Immediate»;

} else if (typeof timer.interval !== «undefined») {

return «Interval»;

} else {

return «Timeout»;

}

}



function clearTimer(clock, timerId, ttype) {

if (!timerId) {

// null appears to be allowed in most browsers, and appears to be

// relied upon by some libraries, like Bootstrap carousel

帰る

}



if (!clock.timers) {

clock.timers = [];

}



// in Node, timerId is an object with .ref()/.unref(), and

// its .id field is the actual timer id.

if (typeof timerId === «object») {

timerId = timerId.id;

}



if (clock.timers.hasOwnProperty(timerId)) {

// check that the ID matches a timer of the correct type

var timer = clock.timers[timerId];

if (timerType(timer) === ttype) {

delete clock.timers[timerId];

} else {

throw new Error(«Cannot clear timer: timer created with set» + ttype + "() but cleared with clear" + timerType(timer) + "()");

}

}

}



function uninstall(clock, target) {

var method,

i,

l;



for (i = 0, l = clock.methods.length; i < l; i++) {

method = clock.methods[i];



if (target[method].hadOwnProperty) {

target[method] = clock["_" + method];

} else {

{

delete target[method];

} catch (ignore) {}

}

}



// Prevent multiple executions which will completely remove these props

clock.methods = [];

}



function hijackMethod(target, method, clock) {

var prop;



clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);

clock["_" + method] = target[method];



if (method === «Date») {

var date = mirrorDateProperties(clock[method], target[method]);

target[method] = date;

} else {

target[method] = function () {

return clock[method].apply(clock, arguments);

};



for (prop in clock[method]) {

if (clock[method].hasOwnProperty(prop)) {

target[method][prop] = clock[method][prop];

}

}

}



target[method].clock = clock;

}



var timers = {

setTimeout: setTimeout,

clearTimeout: clearTimeout,

setImmediate: global.setImmediate,

clearImmediate: global.clearImmediate,

setInterval: setInterval,

clearInterval: clearInterval,

Date: Date

};



var keys = Object.keys || function (obj) {

var ks = [],

key;



for (key in obj) {

if (obj.hasOwnProperty(key)) {

ks.push(key);

}

}



return ks;

};



exports.timers = timers;



function createClock(now) {

var clock = {

now: getEpoch(now),

timeouts: {},

Date: createDate()

};



clock.Date.clock = clock;



clock.setTimeout = function setTimeout(func, timeout) {

return addTimer(clock, {

func: func,

args: Array.prototype.slice.call(arguments, 2),

delay: timeout

});

};



clock.clearTimeout = function clearTimeout(timerId) {

return clearTimer(clock, timerId, «Timeout»);

};



clock.setInterval = function setInterval(func, timeout) {

return addTimer(clock, {

func: func,

args: Array.prototype.slice.call(arguments, 2),

delay: timeout,

interval: timeout

});

};



clock.clearInterval = function clearInterval(timerId) {

return clearTimer(clock, timerId, «Interval»);

};



clock.setImmediate = function setImmediate(func) {

return addTimer(clock, {

func: func,

args: Array.prototype.slice.call(arguments, 1),

immediate: true

});

};



clock.clearImmediate = function clearImmediate(timerId) {

return clearTimer(clock, timerId, «Immediate»);

};



clock.tick = function tick(ms) {

ms = typeof ms === «number»? ms: parseTime(ms);

var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;

var timer = firstTimerInRange(clock, tickFrom, tickTo);

var oldNow;



clock.duringTick = true;



var firstException;

while (timer && tickFrom <= tickTo) {

if (clock.timers[timer.id]) {

tickFrom = clock.now = timer.callAt;

{

oldNow = clock.now;

callTimer(clock, timer);

// compensate for any setSystemTime() call during timer callback

if (oldNow !== clock.now) {

tickFrom += clock.now — oldNow;

tickTo += clock.now — oldNow;

previous += clock.now — oldNow;

}

} catch (e) {

firstException = firstException || e;

}

}



timer = firstTimerInRange(clock, previous, tickTo);

previous = tickFrom;

}



clock.duringTick = false;

clock.now = tickTo;



if (firstException) {

throw firstException;

}



return clock.now;

};



clock.reset = function reset() {

clock.timers = {};

};



clock.setSystemTime = function setSystemTime(now) {

// determine time difference

var newNow = getEpoch(now);

var difference = newNow — clock.now;



// update 'system clock'

clock.now = newNow;



// update timers and intervals to keep them stable

for (var id in clock.timers) {

if (clock.timers.hasOwnProperty(id)) {

var timer = clock.timers[id];

timer.createdAt += difference;

timer.callAt += difference;

}

}

};



return clock;

}

exports.createClock = createClock;



exports.install = function install(target, now, toFake) {

var i,

l;



if (typeof target === «number») {

toFake = now;

now = target;

target = null;

}



if (!target) {

target = global;

}



var clock = createClock(now);



clock.uninstall = function () {

uninstall(clock, target);

};



clock.methods = toFake || [];



if (clock.methods.length === 0) {

clock.methods = keys(timers);

}



for (i = 0, l = clock.methods.length; i < l; i++) {

hijackMethod(target, clock.methods[i], clock);

}



return clock;

};



}(global || this));



}).call(this,typeof global !== «undefined»? global: typeof self !== «undefined»? self: typeof window !== «undefined»? window: {})

},{}]},{},[1])(1)

});

})();

var define;

/**

* Sinon core utilities. For internal use only.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

var sinon = (function () {

«use strict»;

// eslint-disable-line no-unused-vars



var sinonModule;

var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

sinonModule = module.exports = require("./sinon/util/core");

require("./sinon/extend");

require("./sinon/walk");

require("./sinon/typeOf");

require("./sinon/times_in_words");

require("./sinon/spy");

require("./sinon/call");

require("./sinon/behavior");

require("./sinon/stub");

require("./sinon/mock");

require("./sinon/collection");

require("./sinon/assert");

require("./sinon/sandbox");

require("./sinon/test");

require("./sinon/test_case");

require("./sinon/match");

require("./sinon/format");

require("./sinon/log_error");

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require, module.exports, module);

sinonModule = module.exports;

} else {

sinonModule = {};

}



return sinonModule;

}());



/**

* depend ../../sinon.js

* /

/**

* Sinon core utilities. For internal use only.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



var div = typeof document !== «undefined» && document.createElement(«div»);

var hasOwn = Object.prototype.hasOwnProperty;



function isDOMNode(obj) {

var success = false;



{

obj.appendChild(div);

success = div.parentNode === obj;

} catch (e) {

falseを返します。

} finally {

{

obj.removeChild(div);

} catch (e) {

// Remove failed, not much we can do about that

}

}



return success;

}



function isElement(obj) {

return div && obj && obj.nodeType === 1 && isDOMNode(obj);

}



function isFunction(obj) {

return typeof obj === «function» || !!(obj && obj.constructor && obj.call && obj.apply);

}



function isReallyNaN(val) {

return typeof val === «number» && isNaN(val);

}



function mirrorProperties(target, source) {

for (var prop in source) {

if (!hasOwn.call(target, prop)) {

target[prop] = source[prop];

}

}

}



function isRestorable(obj) {

return typeof obj === «function» && typeof obj.restore === «function» && obj.restore.sinon;

}



// Cheap way to detect if we have ES5 support.

var hasES5Support = «keys» in Object;



function makeApi(sinon) {

sinon.wrapMethod = function wrapMethod(object, property, method) {

if (!object) {

throw new TypeError(«Should wrap property of object»);

}



if (typeof method !== «function» && typeof method !== «object») {

throw new TypeError(«Method wrapper should be a function or a property descriptor»);

}



function checkWrappedMethod(wrappedMethod) {

var error;



if (!isFunction(wrappedMethod)) {

error = new TypeError(«Attempted to wrap » + (typeof wrappedMethod) + " property " +

property + " as function");

} else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {

error = new TypeError(«Attempted to wrap » + property + " which is already wrapped");

} else if (wrappedMethod.calledBefore) {

var verb = wrappedMethod.returns? «stubbed»: «spied on»;

error = new TypeError(«Attempted to wrap » + property + " which is already " + verb);

}



if (error) {

if (wrappedMethod && wrappedMethod.stackTrace) {

error.stack += "\n--------------\n" + wrappedMethod.stackTrace;

}

throw error;

}

}



var error, wrappedMethod, i;



// IE 8 does not support hasOwnProperty on the window object and Firefox has a problem

// when using hasOwn.call on objects from other frames.

var owned = object.hasOwnProperty? object.hasOwnProperty(property): hasOwn.call(object, property);



if (hasES5Support) {

var methodDesc = (typeof method === «function»)? {value: method}: method;

var wrappedMethodDesc = sinon.getPropertyDescriptor(object, property);



if (!wrappedMethodDesc) {

error = new TypeError(«Attempted to wrap » + (typeof wrappedMethod) + " property " +

property + " as function");

} else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) {

error = new TypeError(«Attempted to wrap » + property + " which is already wrapped");

}

if (error) {

if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) {

error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace;

}

throw error;

}



var types = sinon.objectKeys(methodDesc);

for (i = 0; i < types.length; i++) {

wrappedMethod = wrappedMethodDesc[types[i]];

checkWrappedMethod(wrappedMethod);

}



mirrorProperties(methodDesc, wrappedMethodDesc);

for (i = 0; i < types.length; i++) {

mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]);

}

Object.defineProperty(object, property, methodDesc);

} else {

wrappedMethod = object[property];

checkWrappedMethod(wrappedMethod);

object[property] = method;

method.displayName = property;

}



method.displayName = property;



// Set up a stack trace which can be used later to find what line of

// code the original method was created on.

method.stackTrace = (new Error(«Stack Trace for original»)).stack;



method.restore = function () {

// For prototype properties try to reset by delete first.

// If this fails (ex: localStorage on mobile safari) then force a reset

// via direct assignment.

if (!owned) {

// In some cases `delete` may throw an error

{

delete object[property];

} catch (e) {} // eslint-disable-line no-empty

// For native code functions `delete` fails without throwing an error

// on Chrome < 43, PhantomJS, etc.

} else if (hasES5Support) {

Object.defineProperty(object, property, wrappedMethodDesc);

}



// Use strict equality comparison to check failures then force a reset

// via direct assignment.

if (object[property] === method) {

object[property] = wrappedMethod;

}

};



method.restore.sinon = true;



if (!hasES5Support) {

mirrorProperties(method, wrappedMethod);

}



return method;

};



sinon.create = function create(proto) {

var F = function () {};

F.prototype = proto;

return new F();

};



sinon.deepEqual = function deepEqual(a, b) {

if (sinon.match && sinon.match.isMatcher(a)) {

return a.test(b);

}



if (typeof a !== «object» || typeof b !== «object») {

return isReallyNaN(a) && isReallyNaN(b) || a === b;

}



if (isElement(a) || isElement(b)) {

return a === b;

}



if (a === b) {

return true;

}



if ((a === null && b !== null) || (a !== null && b === null)) {

falseを返します。

}



if (a instanceof RegExp && b instanceof RegExp) {

return (a.source === b.source) && (a.global === b.global) &&

(a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);

}



var aString = Object.prototype.toString.call(a);

if (aString !== Object.prototype.toString.call(b)) {

falseを返します。

}



if (aString === "[object Date]") {

return a.valueOf() === b.valueOf();

}



var prop;

var aLength = 0;

var bLength = 0;



if (aString === "[object Array]" && a.length !== b.length) {

falseを返します。

}



for (prop in a) {

if (a.hasOwnProperty(prop)) {

aLength += 1;



if (!(prop in b)) {

falseを返します。

}



if (!deepEqual(a[prop], b[prop])) {

falseを返します。

}

}

}



for (prop in b) {

if (b.hasOwnProperty(prop)) {

bLength += 1;

}

}



return aLength === bLength;

};



sinon.functionName = function functionName(func) {

var name = func.displayName || func.name;



// Use function decomposition as a last resort to get function

// name. Does not rely on function decomposition to work — if it

// doesn't debugging will be slightly less informative

// (ie toString will say 'spy' rather than 'myFunc').

if (!name) {

var matches = func.toString().match(/function ([^\s\(]+)/);

name = matches && matches[1];

}



return name;

};



sinon.functionToString = function toString() {

if (this.getCall && this.callCount) {

var thisValue,

prop;

var i = this.callCount;



while (i--) {

thisValue = this.getCall(i).thisValue;



for (prop in thisValue) {

if (thisValue[prop] === this) {

return prop;

}

}

}

}



return this.displayName || «sinon fake»;

};



sinon.objectKeys = function objectKeys(obj) {

if (obj !== Object(obj)) {

throw new TypeError(«sinon.objectKeys called on a non-object»);

}



var keys = [];

var key;

for (key in obj) {

if (hasOwn.call(obj, key)) {

keys.push(key);

}

}



return keys;

};



sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) {

var proto = object;

var descriptor;



while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) {

proto = Object.getPrototypeOf(proto);

}

return descriptor;

};



sinon.getConfig = function (custom) {

var config = {};

custom = custom || {};

var defaults = sinon.defaultConfig;



for (var prop in defaults) {

if (defaults.hasOwnProperty(prop)) {

config[prop] = custom.hasOwnProperty(prop)? custom[prop]: defaults[prop];

}

}



return config;

};



sinon.defaultConfig = {

injectIntoThis: true,

injectInto: null,

properties: [«spy», «stub», «mock», «clock», «server», «requests»],

useFakeTimers: true,

useFakeServer: true

};



sinon.timesInWords = function timesInWords(count) {

return count === 1 && «once» ||

count === 2 && «twice» ||

count === 3 && «thrice» ||

(count || 0) + " times";

};



sinon.calledInOrder = function (spies) {

for (var i = 1, l = spies.length; i < l; i++) {

if (!spies[i — 1].calledBefore(spies[i]) || !spies[i].called) {

falseを返します。

}

}



return true;

};



sinon.orderByFirstCall = function (spies) {

return spies.sort(function (a, b) {

// uuid, won't ever be equal

var aCall = a.getCall(0);

var bCall = b.getCall(0);

var aId = aCall && aCall.callId || -1;

var bId = bCall && bCall.callId || -1;



return aId < bId? -1: 1;

});

};



sinon.createStubInstance = function (constructor) {

if (typeof constructor !== «function») {

throw new TypeError(«The constructor should be a function.»);

}

return sinon.stub(sinon.create(constructor.prototype));

};



sinon.restore = function (object) {

if (object !== null && typeof object === «object») {

for (var prop in object) {

if (isRestorable(object[prop])) {

object[prop].restore();

}

}

} else if (isRestorable(object)) {

object.restore();

}

};



return sinon;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports) {

makeApi(exports);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* /

(function (sinonGlobal) {



function makeApi(sinon) {



// Adapted from developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug

var hasDontEnumBug = (function () {

var obj = {

constructor: function () {

return «0»;

}、

toString: function () {

return «1»;

}、

valueOf: function () {

return «2»;

}、

toLocaleString: function () {

return «3»;

}、

prototype: function () {

return «4»;

}、

isPrototypeOf: function () {

return «5»;

}、

propertyIsEnumerable: function () {

return «6»;

}、

hasOwnProperty: function () {

return «7»;

}、

length: function () {

return «8»;

}、

unique: function () {

return «9»;

}

};



var result = [];

for (var prop in obj) {

if (obj.hasOwnProperty(prop)) {

result.push(obj[prop]());

}

}

return result.join("") !== «0123456789»;

})();



/* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will

* override properties in previous sources.

*

* target — The Object to extend

* sources — Objects to copy properties from.

*

* Returns the extended target

* /

function extend(target /*, sources */) {

var sources = Array.prototype.slice.call(arguments, 1);

var source, i, prop;



for (i = 0; i < sources.length; i++) {

source = sources[i];



for (prop in source) {

if (source.hasOwnProperty(prop)) {

target[prop] = source[prop];

}

}



// Make sure we copy (own) toString method even when in JScript with DontEnum bug

// See developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug

if (hasDontEnumBug && source.hasOwnProperty(«toString») && source.toString !== target.toString) {

target.toString = source.toString;

}

}



return target;

}



sinon.extend = extend;

return sinon.extend;

}



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

module.exports = makeApi(sinon);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* /

(function (sinonGlobal) {



function makeApi(sinon) {



function timesInWords(count) {

switch (count) {

ケース1:

return «once»;

ケース2:

return «twice»;

ケース3:

return «thrice»;

デフォルト:

return (count || 0) + " times";

}

}



sinon.timesInWords = timesInWords;

return sinon.timesInWords;

}



function loadDependencies(require, exports, module) {

var core = require("./util/core");

module.exports = makeApi(core);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* /

/**

* Format functions

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2014 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

function typeOf(value) {

if (value === null) {

return «null»;

} else if (value === undefined) {

return «undefined»;

}

var string = Object.prototype.toString.call(value);

return string.substring(8, string.length — 1).toLowerCase();

}



sinon.typeOf = typeOf;

return sinon.typeOf;

}



function loadDependencies(require, exports, module) {

var core = require("./util/core");

module.exports = makeApi(core);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend typeOf.js

* /

/*jslint eqeqeq: false, onevar: false, plusplus: false*/

/*global module, require, sinon*/

/**

* Match functions

*

* author Maximilian Antoni (mail@maxantoni.de)

* @license BSD

*

* Copyright © 2012 Maximilian Antoni

* /

(function (sinonGlobal) {



function makeApi(sinon) {

function assertType(value, type, name) {

var actual = sinon.typeOf(value);

if (actual !== type) {

throw new TypeError(«Expected type of » + name + " to be " +

type + ", but was " + actual);

}

}



var matcher = {

toString: function () {

return this.message;

}

};



function isMatcher(object) {

return matcher.isPrototypeOf(object);

}



function matchObject(expectation, actual) {

if (actual === null || actual === undefined) {

falseを返します。

}

for (var key in expectation) {

if (expectation.hasOwnProperty(key)) {

var exp = expectation[key];

var act = actual[key];

if (isMatcher(exp)) {

if (!exp.test(act)) {

falseを返します。

}

} else if (sinon.typeOf(exp) === «object») {

if (!matchObject(exp, act)) {

falseを返します。

}

} else if (!sinon.deepEqual(exp, act)) {

falseを返します。

}

}

}

return true;

}



function match(expectation, message) {

var m = sinon.create(matcher);

var type = sinon.typeOf(expectation);

switch (type) {

case «object»:

if (typeof expectation.test === «function») {

m.test = function (actual) {

return expectation.test(actual) === true;

};

m.message = «match(» + sinon.functionName(expectation.test) + ")";

return m;

}

var str = [];

for (var key in expectation) {

if (expectation.hasOwnProperty(key)) {

str.push(key + ": " + expectation[key]);

}

}

m.test = function (actual) {

return matchObject(expectation, actual);

};

m.message = «match(» + str.join(", ") + ")";

休憩;

case «number»:

m.test = function (actual) {

// we need type coercion here

return expectation == actual; // eslint-disable-line eqeqeq

};

休憩;

case «string»:

m.test = function (actual) {

if (typeof actual !== «string») {

falseを返します。

}

return actual.indexOf(expectation) !== -1;

};

m.message = «match(\»" + expectation + "\")";

休憩;

case «regexp»:

m.test = function (actual) {

if (typeof actual !== «string») {

falseを返します。

}

return expectation.test(actual);

};

休憩;

case «function»:

m.test = expectation;

if (message) {

m.message = message;

} else {

m.message = «match(» + sinon.functionName(expectation) + ")";

}

休憩;

デフォルト:

m.test = function (actual) {

return sinon.deepEqual(expectation, actual);

};

}

if (!m.message) {

m.message = «match(» + expectation + ")";

}

return m;

}



matcher.or = function (m2) {

if (!arguments.length) {

throw new TypeError(«Matcher expected»);

} else if (!isMatcher(m2)) {

m2 = match(m2);

}

var m1 = this;

var or = sinon.create(matcher);

or.test = function (actual) {

return m1.test(actual) || m2.test(actual);

};

or.message = m1.message + ".or(" + m2.message + ")";

return or;

};



matcher.and = function (m2) {

if (!arguments.length) {

throw new TypeError(«Matcher expected»);

} else if (!isMatcher(m2)) {

m2 = match(m2);

}

var m1 = this;

var and = sinon.create(matcher);

and.test = function (actual) {

return m1.test(actual) && m2.test(actual);

};

and.message = m1.message + ".and(" + m2.message + ")";

return and;

};



match.isMatcher = isMatcher;



match.any = match(function () {

return true;

}, «any»);



match.defined = match(function (actual) {

return actual !== null && actual !== undefined;

}, «defined»);



match.truthy = match(function (actual) {

return !!actual;

}, «truthy»);



match.falsy = match(function (actual) {

return !actual;

}, «falsy»);



match.same = function (expectation) {

return match(function (actual) {

return expectation === actual;

}, «same(» + expectation + ")");

};



match.typeOf = function (type) {

assertType(type, «string», «type»);

return match(function (actual) {

return sinon.typeOf(actual) === type;

}, «typeOf(\»" + type + "\")");

};



match.instanceOf = function (type) {

assertType(type, «function», «type»);

return match(function (actual) {

return actual instanceof type;

}, «instanceOf(» + sinon.functionName(type) + ")");

};



function createPropertyMatcher(propertyTest, messagePrefix) {

return function (property, value) {

assertType(property, «string», «property»);

var onlyProperty = arguments.length === 1;

var message = messagePrefix + "(\"" + property + "\"";

if (!onlyProperty) {

message += ", " + value;

}

message += ")";

return match(function (actual) {

if (actual === undefined || actual === null ||

!propertyTest(actual, property)) {

falseを返します。

}

return onlyProperty || sinon.deepEqual(value, actual[property]);

}, message);

};

}



match.has = createPropertyMatcher(function (actual, property) {

if (typeof actual === «object») {

return property in actual;

}

return actual[property] !== undefined;

}, «has»);



match.hasOwn = createPropertyMatcher(function (actual, property) {

return actual.hasOwnProperty(property);

}, «hasOwn»);



match.bool = match.typeOf(«boolean»);

match.number = match.typeOf(«number»);

match.string = match.typeOf(«string»);

match.object = match.typeOf(«object»);

match.func = match.typeOf(«function»);

match.array = match.typeOf(«array»);

match.regexp = match.typeOf(«regexp»);

match.date = match.typeOf(«date»);



sinon.match = match;

return match;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./typeOf");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* /

/**

* Format functions

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2014 Christian Johansen

* /

(function (sinonGlobal, formatio) {



function makeApi(sinon) {

function valueFormatter(value) {

return "" + value;

}



function getFormatioFormatter() {

var formatter = formatio.configure({

quoteStrings: false,

limitChildrenCount: 250

});



function format() {

return formatter.ascii.apply(formatter, arguments);

}



return format;

}



function getNodeFormatter() {

{

var util = require(«util»);

} catch (e) {

/* Node, but no util module — would be very old, but better safe than sorry */

}



function format(v) {

var isObjectWithNativeToString = typeof v === «object» && v.toString === Object.prototype.toString;

return isObjectWithNativeToString? util.inspect(v): v;

}



return util? format: valueFormatter;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var formatter;



if (isNode) {

{

formatio = require(«formatio»);

}

catch (e) {} // eslint-disable-line no-empty

}



if (formatio) {

formatter = getFormatioFormatter();

} else if (isNode) {

formatter = getNodeFormatter();

} else {

formatter = valueFormatter;

}



sinon.format = formatter;

return sinon.format;

}



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

module.exports = makeApi(sinon);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon, // eslint-disable-line no-undef

typeof formatio === «object» && formatio // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend match.js

* depend format.js

* /

/**

* Spy calls

*

* author Christian Johansen (christian@cjohansen.no)

* author Maximilian Antoni (mail@maxantoni.de)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* Copyright © 2013 Maximilian Antoni

* /

(function (sinonGlobal) {



var slice = Array.prototype.slice;



function makeApi(sinon) {

function throwYieldError(proxy, text, args) {

var msg = sinon.functionName(proxy) + text;

if (args.length) {

msg += " Received [" + slice.call(args).join(", ") + "]";

}

throw new Error(msg);

}



var callProto = {

calledOn: function calledOn(thisValue) {

if (sinon.match && sinon.match.isMatcher(thisValue)) {

return thisValue.test(this.thisValue);

}

return this.thisValue === thisValue;

}、



calledWith: function calledWith() {

var l = arguments.length;

if (l > this.args.length) {

falseを返します。

}

for (var i = 0; i < l; i += 1) {

if (!sinon.deepEqual(arguments[i], this.args[i])) {

falseを返します。

}

}



return true;

}、



calledWithMatch: function calledWithMatch() {

var l = arguments.length;

if (l > this.args.length) {

falseを返します。

}

for (var i = 0; i < l; i += 1) {

var actual = this.args[i];

var expectation = arguments[i];

if (!sinon.match || !sinon.match(expectation).test(actual)) {

falseを返します。

}

}

return true;

}、



calledWithExactly: function calledWithExactly() {

return arguments.length === this.args.length &&

this.calledWith.apply(this, arguments);

}、



notCalledWith: function notCalledWith() {

return !this.calledWith.apply(this, arguments);

}、



notCalledWithMatch: function notCalledWithMatch() {

return !this.calledWithMatch.apply(this, arguments);

}、



returned: function returned(value) {

return sinon.deepEqual(value, this.returnValue);

}、



threw: function threw(error) {

if (typeof error === «undefined» || !this.exception) {

return !!this.exception;

}



return this.exception === error || this.exception.name === error;

}、



calledWithNew: function calledWithNew() {

return this.proxy.prototype && this.thisValue instanceof this.proxy;

}、



calledBefore: function (other) {

return this.callId < other.callId;

}、



calledAfter: function (other) {

return this.callId > other.callId;

}、



callArg: function (pos) {

this.args[pos]();

}、



callArgOn: function (pos, thisValue) {

this.args[pos].apply(thisValue);

}、



callArgWith: function (pos) {

this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));

}、



callArgOnWith: function (pos, thisValue) {

var args = slice.call(arguments, 2);

this.args[pos].apply(thisValue, args);

}、



«yield»: function () {

this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));

}、



yieldOn: function (thisValue) {

var args = this.args;

for (var i = 0, l = args.length; i < l; ++i) {

if (typeof args[i] === «function») {

args[i].apply(thisValue, slice.call(arguments, 1));

帰る

}

}

throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);

}、



yieldTo: function (prop) {

this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));

}、



yieldToOn: function (prop, thisValue) {

var args = this.args;

for (var i = 0, l = args.length; i < l; ++i) {

if (args[i] && typeof args[i][prop] === «function») {

args[i][prop].apply(thisValue, slice.call(arguments, 2));

帰る

}

}

throwYieldError(this.proxy, " cannot yield to '" + prop +

"' since no callback was passed.", args);

}、



getStackFrames: function () {

// Omit the error message and the two top stack frames in sinon itself:

return this.stack && this.stack.split("\n").slice(3);

}、



toString: function () {

var callStr = this.proxy.toString() + "(";

var args = [];



for (var i = 0, l = this.args.length; i < l; ++i) {

args.push(sinon.format(this.args[i]));

}



callStr = callStr + args.join(", ") + ")";



if (typeof this.returnValue !== «undefined») {

callStr += " => " + sinon.format(this.returnValue);

}



if (this.exception) {

callStr += " !" + this.exception.name;



if (this.exception.message) {

callStr += "(" + this.exception.message + ")";

}

}

if (this.stack) {

callStr += this.getStackFrames()[0].replace(/^\s*(?:at\s+|@)?/, " at ");



}



return callStr;

}

};



callProto.invokeCallback = callProto.yield;



function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) {

if (typeof id !== «number») {

throw new TypeError(«Call id is not a number»);

}

var proxyCall = sinon.create(callProto);

proxyCall.proxy = spy;

proxyCall.thisValue = thisValue;

proxyCall.args = args;

proxyCall.returnValue = returnValue;

proxyCall.exception = exception;

proxyCall.callId = id;

proxyCall.stack = stack;



return proxyCall;

}

createSpyCall.toString = callProto.toString; // used by mocks



sinon.spyCall = createSpyCall;

return createSpyCall;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./match");

require("./format");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend times_in_words.js

* depend util/core.js

* depend extend.js

* depend call.js

* depend format.js

* /

/**

* Spy functions

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

var push = Array.prototype.push;

var slice = Array.prototype.slice;

var callId = 0;



function spy(object, property, types) {

if (!property && typeof object === «function») {

return spy.create(object);

}



if (!object && !property) {

return spy.create(function () { });

}



if (types) {

var methodDesc = sinon.getPropertyDescriptor(object, property);

for (var i = 0; i < types.length; i++) {

methodDesc[types[i]] = spy.create(methodDesc[types[i]]);

}

return sinon.wrapMethod(object, property, methodDesc);

}



return sinon.wrapMethod(object, property, spy.create(object[property]));

}



function matchingFake(fakes, args, strict) {

if (!fakes) {

return undefined;

}



for (var i = 0, l = fakes.length; i < l; i++) {

if (fakes[i].matches(args, strict)) {

return fakes[i];

}

}

}



function incrementCallCount() {

this.called = true;

this.callCount += 1;

this.notCalled = false;

this.calledOnce = this.callCount === 1;

this.calledTwice = this.callCount === 2;

this.calledThrice = this.callCount === 3;

}



function createCallProperties() {

this.firstCall = this.getCall(0);

this.secondCall = this.getCall(1);

this.thirdCall = this.getCall(2);

this.lastCall = this.getCall(this.callCount — 1);

}



var vars = «a,b,c,d,e,f,g,h,i,j,k,l»;

function createProxy(func, proxyLength) {

// Retain the function length:

var p;

if (proxyLength) {

eval(«p = (function proxy(» + vars.substring(0, proxyLength * 2 — 1) + // eslint-disable-line no-eval

") { return p.invoke(func, this, slice.call(arguments)); });");

} else {

p = function proxy() {

return p.invoke(func, this, slice.call(arguments));

};

}

p.isSinonProxy = true;

return p;

}



var uuid = 0;



// Public API

var spyApi = {

reset: function () {

if (this.invoking) {

var err = new Error(«Cannot reset Sinon function while invoking it. » +

«Move the call to .reset outside of the callback.»);

err.name = «InvalidResetException»;

throw err;

}



this.called = false;

this.notCalled = true;

this.calledOnce = false;

this.calledTwice = false;

this.calledThrice = false;

this.callCount = 0;

this.firstCall = null;

this.secondCall = null;

this.thirdCall = null;

this.lastCall = null;

this.args = [];

this.returnValues = [];

this.thisValues = [];

this.exceptions = [];

this.callIds = [];

this.stacks = [];

if (this.fakes) {

for (var i = 0; i < this.fakes.length; i++) {

this.fakes[i].reset();

}

}



return this;

}、



create: function create(func, spyLength) {

var name;



if (typeof func !== «function») {

func = function () { };

} else {

name = sinon.functionName(func);

}



if (!spyLength) {

spyLength = func.length;

}



var proxy = createProxy(func, spyLength);



sinon.extend(proxy, spy);

delete proxy.create;

sinon.extend(proxy, func);



proxy.reset();

proxy.prototype = func.prototype;

proxy.displayName = name || «spy»;

proxy.toString = sinon.functionToString;

proxy.instantiateFake = sinon.spy.create;

proxy.id = «spy#» + uuid++;



return proxy;

}、



invoke: function invoke(func, thisValue, args) {

var matching = matchingFake(this.fakes, args);

var exception, returnValue;



incrementCallCount.call(this);

push.call(this.thisValues, thisValue);

push.call(this.args, args);

push.call(this.callIds, callId++);



// Make call properties available from within the spied function:

createCallProperties.call(this);



{

this.invoking = true;



if (matching) {

returnValue = matching.invoke(func, thisValue, args);

} else {

returnValue = (this.func || func).apply(thisValue, args);

}



var thisCall = this.getCall(this.callCount — 1);

if (thisCall.calledWithNew() && typeof returnValue !== «object») {

returnValue = thisValue;

}

} catch (e) {

exception = e;

} finally {

delete this.invoking;

}



push.call(this.exceptions, exception);

push.call(this.returnValues, returnValue);

push.call(this.stacks, new Error().stack);



// Make return value and exception available in the calls:

createCallProperties.call(this);



if (exception !== undefined) {

throw exception;

}



return returnValue;

}、



named: function named(name) {

this.displayName = name;

return this;

}、



getCall: function getCall(i) {

if (i < 0 || i >= this.callCount) {

return null;

}



return sinon.spyCall(this, this.thisValues[i], this.args[i],

this.returnValues[i], this.exceptions[i],

this.callIds[i], this.stacks[i]);

}、



getCalls: function () {

var calls = [];

var i;



for (i = 0; i < this.callCount; i++) {

calls.push(this.getCall(i));

}



return calls;

}、



calledBefore: function calledBefore(spyFn) {

if (!this.called) {

falseを返します。

}



if (!spyFn.called) {

return true;

}



return this.callIds[0] < spyFn.callIds[spyFn.callIds.length — 1];

}、



calledAfter: function calledAfter(spyFn) {

if (!this.called || !spyFn.called) {

falseを返します。

}



return this.callIds[this.callCount — 1] > spyFn.callIds[spyFn.callCount — 1];

}、



withArgs: function () {

var args = slice.call(arguments);



if (this.fakes) {

var match = matchingFake(this.fakes, args, true);



if (match) {

return match;

}

} else {

this.fakes = [];

}



var original = this;

var fake = this.instantiateFake();

fake.matchingAguments = args;

fake.parent = this;

push.call(this.fakes, fake);



fake.withArgs = function () {

return original.withArgs.apply(original, arguments);

};



for (var i = 0; i < this.args.length; i++) {

if (fake.matches(this.args[i])) {

incrementCallCount.call(fake);

push.call(fake.thisValues, this.thisValues[i]);

push.call(fake.args, this.args[i]);

push.call(fake.returnValues, this.returnValues[i]);

push.call(fake.exceptions, this.exceptions[i]);

push.call(fake.callIds, this.callIds[i]);

}

}

createCallProperties.call(fake);



return fake;

}、



matches: function (args, strict) {

var margs = this.matchingAguments;



if (margs.length <= args.length &&

sinon.deepEqual(margs, args.slice(0, margs.length))) {

return !strict || margs.length === args.length;

}

}、



printf: function (format) {

var spyInstance = this;

var args = slice.call(arguments, 1);

var formatter;



return (format || "").replace(/%(.)/g, function (match, specifyer) {

formatter = spyApi.formatters[specifyer];



if (typeof formatter === «function») {

return formatter.call(null, spyInstance, args);

} else if (!isNaN(parseInt(specifyer, 10))) {

return sinon.format(args[specifyer — 1]);

}



return "%" + specifyer;

});

}

};



function delegateToCalls(method, matchAny, actual, notCalled) {

spyApi[method] = function () {

if (!this.called) {

if (notCalled) {

return notCalled.apply(this, arguments);

}

falseを返します。

}



var currentCall;

var matches = 0;



for (var i = 0, l = this.callCount; i < l; i += 1) {

currentCall = this.getCall(i);



if (currentCall[actual || method].apply(currentCall, arguments)) {

matches += 1;



if (matchAny) {

return true;

}

}

}



return matches === this.callCount;

};

}



delegateToCalls(«calledOn», true);

delegateToCalls(«alwaysCalledOn», false, «calledOn»);

delegateToCalls(«calledWith», true);

delegateToCalls(«calledWithMatch», true);

delegateToCalls(«alwaysCalledWith», false, «calledWith»);

delegateToCalls(«alwaysCalledWithMatch», false, «calledWithMatch»);

delegateToCalls(«calledWithExactly», true);

delegateToCalls(«alwaysCalledWithExactly», false, «calledWithExactly»);

delegateToCalls(«neverCalledWith», false, «notCalledWith», function () {

return true;

});

delegateToCalls(«neverCalledWithMatch», false, «notCalledWithMatch», function () {

return true;

});

delegateToCalls(«threw», true);

delegateToCalls(«alwaysThrew», false, «threw»);

delegateToCalls(«returned», true);

delegateToCalls(«alwaysReturned», false, «returned»);

delegateToCalls(«calledWithNew», true);

delegateToCalls(«alwaysCalledWithNew», false, «calledWithNew»);

delegateToCalls(«callArg», false, «callArgWith», function () {

throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");

});

spyApi.callArgWith = spyApi.callArg;

delegateToCalls(«callArgOn», false, «callArgOnWith», function () {

throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");

});

spyApi.callArgOnWith = spyApi.callArgOn;

delegateToCalls(«yield», false, «yield», function () {

throw new Error(this.toString() + " cannot yield since it was not yet invoked.");

});

// «invokeCallback» is an alias for «yield» since «yield» is invalid in strict mode.

spyApi.invokeCallback = spyApi.yield;

delegateToCalls(«yieldOn», false, «yieldOn», function () {

throw new Error(this.toString() + " cannot yield since it was not yet invoked.");

});

delegateToCalls(«yieldTo», false, «yieldTo», function (property) {

throw new Error(this.toString() + " cannot yield to '" + property +

"' since it was not yet invoked.");

});

delegateToCalls(«yieldToOn», false, «yieldToOn», function (property) {

throw new Error(this.toString() + " cannot yield to '" + property +

"' since it was not yet invoked.");

});



spyApi.formatters = {

c: function (spyInstance) {

return sinon.timesInWords(spyInstance.callCount);

}、



n: function (spyInstance) {

return spyInstance.toString();

}、



C: function (spyInstance) {

var calls = [];



for (var i = 0, l = spyInstance.callCount; i < l; ++i) {

var stringifiedCall = " " + spyInstance.getCall(i).toString();

if (/\n/.test(calls[i — 1])) {

stringifiedCall = "\n" + stringifiedCall;

}

push.call(calls, stringifiedCall);

}



return calls.length > 0? "\n" + calls.join("\n"): "";

}、



t: function (spyInstance) {

var objects = [];



for (var i = 0, l = spyInstance.callCount; i < l; ++i) {

push.call(objects, sinon.format(spyInstance.thisValues[i]));

}



return objects.join(", ");

}、



"*": function (spyInstance, args) {

var formatted = [];



for (var i = 0, l = args.length; i < l; ++i) {

push.call(formatted, sinon.format(args[i]));

}



return formatted.join(", ");

}

};



sinon.extend(spy, spyApi);



spy.spyCall = sinon.spyCall;

sinon.spy = spy;



return spy;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var core = require("./util/core");

require("./call");

require("./extend");

require("./times_in_words");

require("./format");

module.exports = makeApi(core);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend extend.js

* /

/**

* Stub behavior

*

* author Christian Johansen (christian@cjohansen.no)

* author Tim Fischbach (mail@timfischbach.de)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



var slice = Array.prototype.slice;

var join = Array.prototype.join;

var useLeftMostCallback = -1;

var useRightMostCallback = -2;



var nextTick = (function () {

if (typeof process === «object» && typeof process.nextTick === «function») {

return process.nextTick;

}



if (typeof setImmediate === «function») {

return setImmediate;

}



return function (callback) {

setTimeout(callback, 0);

};

})();



function throwsException(error, message) {

if (typeof error === «string») {

this.exception = new Error(message || "");

this.exception.name = error;

} else if (!error) {

this.exception = new Error(«Error»);

} else {

this.exception = error;

}



return this;

}



function getCallback(behavior, args) {

var callArgAt = behavior.callArgAt;



if (callArgAt >= 0) {

return args[callArgAt];

}



var argumentList;



if (callArgAt === useLeftMostCallback) {

argumentList = args;

}



if (callArgAt === useRightMostCallback) {

argumentList = slice.call(args).reverse();

}



var callArgProp = behavior.callArgProp;



for (var i = 0, l = argumentList.length; i < l; ++i) {

if (!callArgProp && typeof argumentList[i] === «function») {

return argumentList[i];

}



if (callArgProp && argumentList[i] &&

typeof argumentList[i][callArgProp] === «function») {

return argumentList[i][callArgProp];

}

}



return null;

}



function makeApi(sinon) {

function getCallbackError(behavior, func, args) {

if (behavior.callArgAt < 0) {

var msg;



if (behavior.callArgProp) {

msg = sinon.functionName(behavior.stub) +

" expected to yield to '" + behavior.callArgProp +

"', but no object with such a property was passed.";

} else {

msg = sinon.functionName(behavior.stub) +

" expected to yield, but no callback was passed.";

}



if (args.length > 0) {

msg += " Received [" + join.call(args, ", ") + "]";

}



return msg;

}



return «argument at index » + behavior.callArgAt + " is not a function: " + func;

}



function callCallback(behavior, args) {

if (typeof behavior.callArgAt === «number») {

var func = getCallback(behavior, args);



if (typeof func !== «function») {

throw new TypeError(getCallbackError(behavior, func, args));

}



if (behavior.callbackAsync) {

nextTick(function () {

func.apply(behavior.callbackContext, behavior.callbackArguments);

});

} else {

func.apply(behavior.callbackContext, behavior.callbackArguments);

}

}

}



var proto = {

create: function create(stub) {

var behavior = sinon.extend({}, sinon.behavior);

delete behavior.create;

behavior.stub = stub;



return behavior;

}、



isPresent: function isPresent() {

return (typeof this.callArgAt === «number» ||

this.exception ||

typeof this.returnArgAt === «number» ||

this.returnThis ||

this.returnValueDefined);

}、



invoke: function invoke(context, args) {

callCallback(this, args);



if (this.exception) {

throw this.exception;

} else if (typeof this.returnArgAt === «number») {

return args[this.returnArgAt];

} else if (this.returnThis) {

return context;

}



return this.returnValue;

}、



onCall: function onCall(index) {

return this.stub.onCall(index);

}、



onFirstCall: function onFirstCall() {

return this.stub.onFirstCall();

}、



onSecondCall: function onSecondCall() {

return this.stub.onSecondCall();

}、



onThirdCall: function onThirdCall() {

return this.stub.onThirdCall();

}、



withArgs: function withArgs(/* arguments */) {

throw new Error(

«Defining a stub by invoking \»stub.onCall(...).withArgs(...)\" " +

«is not supported. Use \»stub.withArgs(...).onCall(...)\" " +

«to define sequential behavior for calls with certain arguments.»

);

}、



callsArg: function callsArg(pos) {

if (typeof pos !== «number») {

throw new TypeError(«argument index is not number»);

}



this.callArgAt = pos;

this.callbackArguments = [];

this.callbackContext = undefined;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



callsArgOn: function callsArgOn(pos, context) {

if (typeof pos !== «number») {

throw new TypeError(«argument index is not number»);

}

if (typeof context !== «object») {

throw new TypeError(«argument context is not an object»);

}



this.callArgAt = pos;

this.callbackArguments = [];

this.callbackContext = context;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



callsArgWith: function callsArgWith(pos) {

if (typeof pos !== «number») {

throw new TypeError(«argument index is not number»);

}



this.callArgAt = pos;

this.callbackArguments = slice.call(arguments, 1);

this.callbackContext = undefined;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



callsArgOnWith: function callsArgWith(pos, context) {

if (typeof pos !== «number») {

throw new TypeError(«argument index is not number»);

}

if (typeof context !== «object») {

throw new TypeError(«argument context is not an object»);

}



this.callArgAt = pos;

this.callbackArguments = slice.call(arguments, 2);

this.callbackContext = context;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



yields: function () {

this.callArgAt = useLeftMostCallback;

this.callbackArguments = slice.call(arguments, 0);

this.callbackContext = undefined;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



yieldsRight: function () {

this.callArgAt = useRightMostCallback;

this.callbackArguments = slice.call(arguments, 0);

this.callbackContext = undefined;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



yieldsOn: function (context) {

if (typeof context !== «object») {

throw new TypeError(«argument context is not an object»);

}



this.callArgAt = useLeftMostCallback;

this.callbackArguments = slice.call(arguments, 1);

this.callbackContext = context;

this.callArgProp = undefined;

this.callbackAsync = false;



return this;

}、



yieldsTo: function (prop) {

this.callArgAt = useLeftMostCallback;

this.callbackArguments = slice.call(arguments, 1);

this.callbackContext = undefined;

this.callArgProp = prop;

this.callbackAsync = false;



return this;

}、



yieldsToOn: function (prop, context) {

if (typeof context !== «object») {

throw new TypeError(«argument context is not an object»);

}



this.callArgAt = useLeftMostCallback;

this.callbackArguments = slice.call(arguments, 2);

this.callbackContext = context;

this.callArgProp = prop;

this.callbackAsync = false;



return this;

}、



throws: throwsException,

throwsException: throwsException,



returns: function returns(value) {

this.returnValue = value;

this.returnValueDefined = true;

this.exception = undefined;



return this;

}、



returnsArg: function returnsArg(pos) {

if (typeof pos !== «number») {

throw new TypeError(«argument index is not number»);

}



this.returnArgAt = pos;



return this;

}、



returnsThis: function returnsThis() {

this.returnThis = true;



return this;

}

};



function createAsyncVersion(syncFnName) {

return function () {

var result = this[syncFnName].apply(this, arguments);

this.callbackAsync = true;

return result;

};

}



// create asynchronous versions of callsArg* and yields* methods

for (var method in proto) {

// need to avoid creating anotherasync versions of the newly added async methods

if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) {

proto[method + «Async»] = createAsyncVersion(method);

}

}



sinon.behavior = proto;

return proto;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./extend");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* /

(function (sinonGlobal) {



function makeApi(sinon) {

function walkInternal(obj, iterator, context, originalObj, seen) {

var proto, prop;



if (typeof Object.getOwnPropertyNames !== «function») {

// We explicitly want to enumerate through all of the prototype's properties

// in this case, therefore we deliberately leave out an own property check.

/* eslint-disable guard-for-in */

for (prop in obj) {

iterator.call(context, obj[prop], prop, obj);

}

/* eslint-enable guard-for-in */



帰る

}



Object.getOwnPropertyNames(obj).forEach(function (k) {

if (!seen[k]) {

seen[k] = true;

var target = typeof Object.getOwnPropertyDescriptor(obj, k).get === «function»?

originalObj: obj;

iterator.call(context, target[k], k, target);

}

});



proto = Object.getPrototypeOf(obj);

if (proto) {

walkInternal(proto, iterator, context, originalObj, seen);

}

}



/* Public: walks the prototype chain of an object and iterates over every own property

* name encountered. The iterator is called in the same fashion that Array.prototype.forEach

* works, where it is passed the value, key, and own object as the 1st, 2nd, and 3rd positional

* argument, respectively. In cases where Object.getOwnPropertyNames is not available, walk will

* default to using a simple for..in loop.

*

* obj — The object to walk the prototype chain for.

* iterator — The function to be called on each pass of the walk.

* context — (Optional) When given, the iterator will be called with this object as the receiver.

* /

function walk(obj, iterator, context) {

return walkInternal(obj, iterator, context, obj, {});

}



sinon.walk = walk;

return sinon.walk;

}



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

module.exports = makeApi(sinon);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend extend.js

* depend spy.js

* depend behavior.js

* depend walk.js

* /

/**

* Stub functions

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

function stub(object, property, func) {

if (!!func && typeof func !== «function» && typeof func !== «object») {

throw new TypeError(«Custom stub should be a function or a property descriptor»);

}



var wrapper;



if (func) {

if (typeof func === «function») {

wrapper = sinon.spy && sinon.spy.create? sinon.spy.create(func): func;

} else {

wrapper = func;

if (sinon.spy && sinon.spy.create) {

var types = sinon.objectKeys(wrapper);

for (var i = 0; i < types.length; i++) {

wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]);

}

}

}

} else {

var stubLength = 0;

if (typeof object === «object» && typeof object[property] === «function») {

stubLength = object[property].length;

}

wrapper = stub.create(stubLength);

}



if (!object && typeof property === «undefined») {

return sinon.stub.create();

}



if (typeof property === «undefined» && typeof object === «object») {

sinon.walk(object || {}, function (value, prop, propOwner) {

// we don't want to stub things like toString(), valueOf(), etc. so we only stub if the object

// is not Object.prototype

if (

propOwner !== Object.prototype &&

prop !== «constructor» &&

typeof sinon.getPropertyDescriptor(propOwner, prop).value === «function»

){

stub(object, prop);

}

});



return object;

}



return sinon.wrapMethod(object, property, wrapper);

}



/*eslint-disable no-use-before-define*/

function getParentBehaviour(stubInstance) {

return (stubInstance.parent && getCurrentBehavior(stubInstance.parent));

}



function getDefaultBehavior(stubInstance) {

return stubInstance.defaultBehavior ||

getParentBehaviour(stubInstance) ||

sinon.behavior.create(stubInstance);

}



function getCurrentBehavior(stubInstance) {

var behavior = stubInstance.behaviors[stubInstance.callCount — 1];

return behavior && behavior.isPresent()? behavior: getDefaultBehavior(stubInstance);

}

/*eslint-enable no-use-before-define*/



var uuid = 0;



var proto = {

create: function create(stubLength) {

var functionStub = function () {

return getCurrentBehavior(functionStub).invoke(this, arguments);

};



functionStub.id = «stub#» + uuid++;

var orig = functionStub;

functionStub = sinon.spy.create(functionStub, stubLength);

functionStub.func = orig;



sinon.extend(functionStub, stub);

functionStub.instantiateFake = sinon.stub.create;

functionStub.displayName = «stub»;

functionStub.toString = sinon.functionToString;



functionStub.defaultBehavior = null;

functionStub.behaviors = [];



return functionStub;

}、



resetBehavior: function () {

var i;



this.defaultBehavior = null;

this.behaviors = [];



delete this.returnValue;

delete this.returnArgAt;

this.returnThis = false;



if (this.fakes) {

for (i = 0; i < this.fakes.length; i++) {

this.fakes[i].resetBehavior();

}

}

}、



onCall: function onCall(index) {

if (!this.behaviors[index]) {

this.behaviors[index] = sinon.behavior.create(this);

}



return this.behaviors[index];

}、



onFirstCall: function onFirstCall() {

return this.onCall(0);

}、



onSecondCall: function onSecondCall() {

return this.onCall(1);

}、



onThirdCall: function onThirdCall() {

return this.onCall(2);

}

};



function createBehavior(behaviorMethod) {

return function () {

this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);

this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);

return this;

};

}



for (var method in sinon.behavior) {

if (sinon.behavior.hasOwnProperty(method) &&

!proto.hasOwnProperty(method) &&

method !== «create» &&

method !== «withArgs» &&

method !== «invoke») {

proto[method] = createBehavior(method);

}

}



sinon.extend(stub, proto);

sinon.stub = stub;



return stub;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var core = require("./util/core");

require("./behavior");

require("./spy");

require("./extend");

module.exports = makeApi(core);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend times_in_words.js

* depend util/core.js

* depend call.js

* depend extend.js

* depend match.js

* depend spy.js

* depend stub.js

* depend format.js

* /

/**

* Mock functions.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

var push = [].push;

var match = sinon.match;



function mock(object) {

// if (typeof console !== undefined && console.warn) {

// console.warn(«mock will be removed from Sinon.JS v2.0»);

// }



if (!object) {

return sinon.expectation.create(«Anonymous mock»);

}



return mock.create(object);

}



function each(collection, callback) {

if (!collection) {

帰る

}



for (var i = 0, l = collection.length; i < l; i += 1) {

callback(collection[i]);

}

}



function arrayEquals(arr1, arr2, compareLength) {

if (compareLength && (arr1.length !== arr2.length)) {

falseを返します。

}



for (var i = 0, l = arr1.length; i < l; i++) {

if (!sinon.deepEqual(arr1[i], arr2[i])) {

falseを返します。

}

}

return true;

}



sinon.extend(mock, {

create: function create(object) {

if (!object) {

throw new TypeError(«object is null»);

}



var mockObject = sinon.extend({}, mock);

mockObject.object = object;

delete mockObject.create;



return mockObject;

}、



expects: function expects(method) {

if (!method) {

throw new TypeError(«method is falsy»);

}



if (!this.expectations) {

this.expectations = {};

this.proxies = [];

}



if (!this.expectations[method]) {

this.expectations[method] = [];

var mockObject = this;



sinon.wrapMethod(this.object, method, function () {

return mockObject.invokeMethod(method, this, arguments);

});



push.call(this.proxies, method);

}



var expectation = sinon.expectation.create(method);

push.call(this.expectations[method], expectation);



return expectation;

}、



restore: function restore() {

var object = this.object;



each(this.proxies, function (proxy) {

if (typeof object[proxy].restore === «function») {

object[proxy].restore();

}

});

}、



verify: function verify() {

var expectations = this.expectations || {};

var messages = [];

var met = [];



each(this.proxies, function (proxy) {

each(expectations[proxy], function (expectation) {

if (!expectation.met()) {

push.call(messages, expectation.toString());

} else {

push.call(met, expectation.toString());

}

});

});



this.restore();



if (messages.length > 0) {

sinon.expectation.fail(messages.concat(met).join("\n"));

} else if (met.length > 0) {

sinon.expectation.pass(messages.concat(met).join("\n"));

}



return true;

}、



invokeMethod: function invokeMethod(method, thisValue, args) {

var expectations = this.expectations && this.expectations[method]? this.expectations[method]: [];

var expectationsWithMatchingArgs = [];

var currentArgs = args || [];

var i, available;



for (i = 0; i < expectations.length; i += 1) {

var expectedArgs = expectations[i].expectedArguments || [];

if (arrayEquals(expectedArgs, currentArgs, expectations[i].expectsExactArgCount)) {

expectationsWithMatchingArgs.push(expectations[i]);

}

}



for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) {

if (!expectationsWithMatchingArgs[i].met() &&

expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) {

return expectationsWithMatchingArgs[i].apply(thisValue, args);

}

}



var messages = [];

var exhausted = 0;



for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) {

if (expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) {

available = available || expectationsWithMatchingArgs[i];

} else {

exhausted += 1;

}

}



if (available && exhausted === 0) {

return available.apply(thisValue, args);

}



for (i = 0; i < expectations.length; i += 1) {

push.call(messages, " " + expectations[i].toString());

}



messages.unshift(«Unexpected call: » + sinon.spyCall.toString.call({

proxy: method,

args: args

}));



sinon.expectation.fail(messages.join("\n"));

}

});



var times = sinon.timesInWords;

var slice = Array.prototype.slice;



function callCountInWords(callCount) {

if (callCount === 0) {

return «never called»;

}



return «called » + times(callCount);

}



function expectedCallCountInWords(expectation) {

var min = expectation.minCalls;

var max = expectation.maxCalls;



if (typeof min === «number» && typeof max === «number») {

var str = times(min);



if (min !== max) {

str = «at least » + str + " and at most " + times(max);

}



return str;

}



if (typeof min === «number») {

return «at least » + times(min);

}



return «at most » + times(max);

}



function receivedMinCalls(expectation) {

var hasMinLimit = typeof expectation.minCalls === «number»;

return !hasMinLimit || expectation.callCount >= expectation.minCalls;

}



function receivedMaxCalls(expectation) {

if (typeof expectation.maxCalls !== «number») {

falseを返します。

}



return expectation.callCount === expectation.maxCalls;

}



function verifyMatcher(possibleMatcher, arg) {

var isMatcher = match && match.isMatcher(possibleMatcher);



return isMatcher && possibleMatcher.test(arg) || true;

}



sinon.expectation = {

minCalls: 1,

maxCalls: 1,



create: function create(methodName) {

var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);

delete expectation.create;

expectation.method = methodName;



return expectation;

}、



invoke: function invoke(func, thisValue, args) {

this.verifyCallAllowed(thisValue, args);



return sinon.spy.invoke.apply(this, arguments);

}、



atLeast: function atLeast(num) {

if (typeof num !== «number») {

throw new TypeError("'" + num + "' is not number");

}



if (!this.limitsSet) {

this.maxCalls = null;

this.limitsSet = true;

}



this.minCalls = num;



return this;

}、



atMost: function atMost(num) {

if (typeof num !== «number») {

throw new TypeError("'" + num + "' is not number");

}



if (!this.limitsSet) {

this.minCalls = null;

this.limitsSet = true;

}



this.maxCalls = num;



return this;

}、



never: function never() {

return this.exactly(0);

}、



once: function once() {

return this.exactly(1);

}、



twice: function twice() {

return this.exactly(2);

}、



thrice: function thrice() {

return this.exactly(3);

}、



exactly: function exactly(num) {

if (typeof num !== «number») {

throw new TypeError("'" + num + "' is not a number");

}



this.atLeast(num);

return this.atMost(num);

}、



met: function met() {

return !this.failed && receivedMinCalls(this);

}、



verifyCallAllowed: function verifyCallAllowed(thisValue, args) {

if (receivedMaxCalls(this)) {

this.failed = true;

sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));

}



if («expectedThis» in this && this.expectedThis !== thisValue) {

sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +

this.expectedThis);

}



if (!(«expectedArguments» in this)) {

帰る

}



if (!args) {

sinon.expectation.fail(this.method + " received no arguments, expected " +

sinon.format(this.expectedArguments));

}



if (args.length < this.expectedArguments.length) {

sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +

"), expected " + sinon.format(this.expectedArguments));

}



if (this.expectsExactArgCount &&

args.length !== this.expectedArguments.length) {

sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +

"), expected " + sinon.format(this.expectedArguments));

}



for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {



if (!verifyMatcher(this.expectedArguments[i], args[i])) {

sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +

", didn't match " + this.expectedArguments.toString());

}



if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {

sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +

", expected " + sinon.format(this.expectedArguments));

}

}

}、



allowsCall: function allowsCall(thisValue, args) {

if (this.met() && receivedMaxCalls(this)) {

falseを返します。

}



if («expectedThis» in this && this.expectedThis !== thisValue) {

falseを返します。

}



if (!(«expectedArguments» in this)) {

return true;

}



args = args || [];



if (args.length < this.expectedArguments.length) {

falseを返します。

}



if (this.expectsExactArgCount &&

args.length !== this.expectedArguments.length) {

falseを返します。

}



for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {

if (!verifyMatcher(this.expectedArguments[i], args[i])) {

falseを返します。

}



if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {

falseを返します。

}

}



return true;

}、



withArgs: function withArgs() {

this.expectedArguments = slice.call(arguments);

return this;

}、



withExactArgs: function withExactArgs() {

this.withArgs.apply(this, arguments);

this.expectsExactArgCount = true;

return this;

}、



on: function on(thisValue) {

this.expectedThis = thisValue;

return this;

}、



toString: function () {

var args = (this.expectedArguments || []).slice();



if (!this.expectsExactArgCount) {

push.call(args, "[...]");

}



var callStr = sinon.spyCall.toString.call({

proxy: this.method || «anonymous mock expectation»,

args: args

});



var message = callStr.replace(", [...", "[, ...") + " " +

expectedCallCountInWords(this);



if (this.met()) {

return «Expectation met: » + message;

}



return «Expected » + message + " (" +

callCountInWords(this.callCount) + ")";

}、



verify: function verify() {

if (!this.met()) {

sinon.expectation.fail(this.toString());

} else {

sinon.expectation.pass(this.toString());

}



return true;

}、



pass: function pass(message) {

sinon.assert.pass(message);

}、



fail: function fail(message) {

var exception = new Error(message);

exception.name = «ExpectationError»;



throw exception;

}

};



sinon.mock = mock;

return mock;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./times_in_words");

require("./call");

require("./extend");

require("./match");

require("./spy");

require("./stub");

require("./format");



module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend spy.js

* depend stub.js

* depend mock.js

* /

/**

* Collections of stubs, spies and mocks.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



var push = [].push;

var hasOwnProperty = Object.prototype.hasOwnProperty;



function getFakes(fakeCollection) {

if (!fakeCollection.fakes) {

fakeCollection.fakes = [];

}



return fakeCollection.fakes;

}



function each(fakeCollection, method) {

var fakes = getFakes(fakeCollection);



for (var i = 0, l = fakes.length; i < l; i += 1) {

if (typeof fakes[i][method] === «function») {

fakes[i][method]();

}

}

}



function compact(fakeCollection) {

var fakes = getFakes(fakeCollection);

var i = 0;

while (i < fakes.length) {

fakes.splice(i, 1);

}

}



function makeApi(sinon) {

var collection = {

verify: function resolve() {

each(this, «verify»);

}、



restore: function restore() {

each(this, «restore»);

compact(this);

}、



reset: function restore() {

each(this, «reset»);

}、



verifyAndRestore: function verifyAndRestore() {

var exception;



{

this.verify();

} catch (e) {

exception = e;

}



this.restore();



if (exception) {

throw exception;

}

}、



add: function add(fake) {

push.call(getFakes(this), fake);

return fake;

}、



spy: function spy() {

return this.add(sinon.spy.apply(sinon, arguments));

}、



stub: function stub(object, property, value) {

if (property) {

var original = object[property];



if (typeof original !== «function») {

if (!hasOwnProperty.call(object, property)) {

throw new TypeError(«Cannot stub non-existent own property » + property);

}



object[property] = value;



return this.add({

restore: function () {

object[property] = original;

}

});

}

}

if (!property && !!object && typeof object === «object») {

var stubbedObj = sinon.stub.apply(sinon, arguments);



for (var prop in stubbedObj) {

if (typeof stubbedObj[prop] === «function») {

this.add(stubbedObj[prop]);

}

}



return stubbedObj;

}



return this.add(sinon.stub.apply(sinon, arguments));

}、



mock: function mock() {

return this.add(sinon.mock.apply(sinon, arguments));

}、



inject: function inject(obj) {

var col = this;



obj.spy = function () {

return col.spy.apply(col, arguments);

};



obj.stub = function () {

return col.stub.apply(col, arguments);

};



obj.mock = function () {

return col.mock.apply(col, arguments);

};



return obj;

}

};



sinon.collection = collection;

return collection;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./mock");

require("./spy");

require("./stub");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* Fake timer API

* setTimeout

* setInterval

* clearTimeout

* clearInterval

* tick

* reset

* Date

*

* Inspired by jsUnitMockTimeOut from JsUnit

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function () {



function makeApi(s, lol) {

/*global lolex */

var llx = typeof lolex !== «undefined»? lolex: lol;



s.useFakeTimers = function () {

var now;

var methods = Array.prototype.slice.call(arguments);



if (typeof methods[0] === «string») {

now = 0;

} else {

now = methods.shift();

}



var clock = llx.install(now || 0, methods);

clock.restore = clock.uninstall;

return clock;

};



s.clock = {

create: function (now) {

return llx.createClock(now);

}

};



s.timers = {

setTimeout: setTimeout,

clearTimeout: clearTimeout,

setImmediate: (typeof setImmediate !== «undefined»? setImmediate: undefined),

clearImmediate: (typeof clearImmediate !== «undefined»? clearImmediate: undefined),

setInterval: setInterval,

clearInterval: clearInterval,

Date: Date

};

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, epxorts, module, lolex) {

var core = require("./core");

makeApi(core, lolex);

module.exports = core;

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require, module.exports, module, require(«lolex»));

} else {

makeApi(sinon); // eslint-disable-line no-undef

}

}());



/**

* Minimal Event interface implementation

*

* Original implementation by Sven Fuchs: gist.github.com/995028

* Modifications and tests by Christian Johansen.

*

* author Sven Fuchs (svenfuchs@artweb-design.de)

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2011 Sven Fuchs, Christian Johansen

* /

if (typeof sinon === «undefined») {

this.sinon = {};

}



(function () {



var push = [].push;



function makeApi(sinon) {

sinon.Event = function Event(type, bubbles, cancelable, target) {

this.initEvent(type, bubbles, cancelable, target);

};



sinon.Event.prototype = {

initEvent: function (type, bubbles, cancelable, target) {

this.type = type;

this.bubbles = bubbles;

this.cancelable = cancelable;

this.target = target;

}、



stopPropagation: function () {},



preventDefault: function () {

this.defaultPrevented = true;

}

};



sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {

this.initEvent(type, false, false, target);

this.loaded = progressEventRaw.loaded || null;

this.total = progressEventRaw.total || null;

this.lengthComputable = !!progressEventRaw.total;

};



sinon.ProgressEvent.prototype = new sinon.Event();



sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;



sinon.CustomEvent = function CustomEvent(type, customData, target) {

this.initEvent(type, false, false, target);

this.detail = customData.detail || null;

};



sinon.CustomEvent.prototype = new sinon.Event();



sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;



sinon.EventTarget = {

addEventListener: function addEventListener(event, listener) {

this.eventListeners = this.eventListeners || {};

this.eventListeners[event] = this.eventListeners[event] || [];

push.call(this.eventListeners[event], listener);

}、



removeEventListener: function removeEventListener(event, listener) {

var listeners = this.eventListeners && this.eventListeners[event] || [];



for (var i = 0, l = listeners.length; i < l; ++i) {

if (listeners[i] === listener) {

return listeners.splice(i, 1);

}

}

}、



dispatchEvent: function dispatchEvent(event) {

var type = event.type;

var listeners = this.eventListeners && this.eventListeners[type] || [];



for (var i = 0; i < listeners.length; i++) {

if (typeof listeners[i] === «function») {

listeners[i].call(this, event);

} else {

listeners[i].handleEvent(event);

}

}



return !!event.defaultPrevented;

}

};

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require) {

var sinon = require("./core");

makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require);

} else {

makeApi(sinon); // eslint-disable-line no-undef

}

}());



/**

* depend util/core.js

* /

/**

* Logs errors

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2014 Christian Johansen

* /

(function (sinonGlobal) {



// cache a reference to setTimeout, so that our reference won't be stubbed out

// when using fake timers and errors will still get logged

// github.com/cjohansen/Sinon.JS/issues/381

var realSetTimeout = setTimeout;



function makeApi(sinon) {



function log() {}



function logError(label, err) {

var msg = label + " threw exception: ";



function throwLoggedError() {

err.message = msg + err.message;

throw err;

}



sinon.log(msg + "[" + err.name + "] " + err.message);



if (err.stack) {

sinon.log(err.stack);

}



if (logError.useImmediateExceptions) {

throwLoggedError();

} else {

logError.setTimeout(throwLoggedError, 0);

}

}



// When set to true, any errors logged will be thrown immediately;

// If set to false, the errors will be thrown in separate execution frame.

logError.useImmediateExceptions = false;



// wrap realSetTimeout with something we can stub in tests

logError.setTimeout = function (func, timeout) {

realSetTimeout(func, timeout);

};



var exports = {};

exports.log = sinon.log = log;

exports.logError = sinon.logError = logError;



return exports;

}



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

module.exports = makeApi(sinon);

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend core.js

* depend ../extend.js

* depend event.js

* depend ../log_error.js

* /

/**

* Fake XDomainRequest object

* /

if (typeof sinon === «undefined») {

this.sinon = {};

}



// wrapper for global

(function (global) {



var xdr = { XDomainRequest: global.XDomainRequest };

xdr.GlobalXDomainRequest = global.XDomainRequest;

xdr.supportsXDR = typeof xdr.GlobalXDomainRequest !== «undefined»;

xdr.workingXDR = xdr.supportsXDR? xdr.GlobalXDomainRequest: false;



function makeApi(sinon) {

sinon.xdr = xdr;



function FakeXDomainRequest() {

this.readyState = FakeXDomainRequest.UNSENT;

this.requestBody = null;

this.requestHeaders = {};

this.status = 0;

this.timeout = null;



if (typeof FakeXDomainRequest.onCreate === «function») {

FakeXDomainRequest.onCreate(this);

}

}



function verifyState(x) {

if (x.readyState !== FakeXDomainRequest.OPENED) {

throw new Error(«INVALID_STATE_ERR»);

}



if (x.sendFlag) {

throw new Error(«INVALID_STATE_ERR»);

}

}



function verifyRequestSent(x) {

if (x.readyState === FakeXDomainRequest.UNSENT) {

throw new Error(«Request not sent»);

}

if (x.readyState === FakeXDomainRequest.DONE) {

throw new Error(«Request done»);

}

}



function verifyResponseBodyType(body) {

if (typeof body !== «string») {

var error = new Error(«Attempted to respond to fake XDomainRequest with » +

body + ", which is not a string.");

error.name = «InvalidBodyException»;

throw error;

}

}



sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {

open: function open(method, url) {

this.method = method;

this.url = url;



this.responseText = null;

this.sendFlag = false;



this.readyStateChange(FakeXDomainRequest.OPENED);

}、



readyStateChange: function readyStateChange(state) {

this.readyState = state;

var eventName = "";

switch (this.readyState) {

case FakeXDomainRequest.UNSENT:

休憩;

case FakeXDomainRequest.OPENED:

休憩;

case FakeXDomainRequest.LOADING:

if (this.sendFlag) {

//raise the progress event

eventName = «onprogress»;

}

休憩;

case FakeXDomainRequest.DONE:

if (this.isTimeout) {

eventName = «ontimeout»;

} else if (this.errorFlag || (this.status < 200 || this.status > 299)) {

eventName = «onerror»;

} else {

eventName = «onload»;

}

休憩;

}



// raising event (if defined)

if (eventName) {

if (typeof this[eventName] === «function») {

{

this[eventName]();

} catch (e) {

sinon.logError(«Fake XHR » + eventName + " handler", e);

}

}

}

}、



send: function send(data) {

verifyState(this);



if (!/^(get|head)$/i.test(this.method)) {

this.requestBody = data;

}

this.requestHeaders[«Content-Type»] = «text/plain;charset=utf-8»;



this.errorFlag = false;

this.sendFlag = true;

this.readyStateChange(FakeXDomainRequest.OPENED);



if (typeof this.onSend === «function») {

this.onSend(this);

}

}、



abort: function abort() {

this.aborted = true;

this.responseText = null;

this.errorFlag = true;



if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {

this.readyStateChange(sinon.FakeXDomainRequest.DONE);

this.sendFlag = false;

}

}、



setResponseBody: function setResponseBody(body) {

verifyRequestSent(this);

verifyResponseBodyType(body);



var chunkSize = this.chunkSize || 10;

var index = 0;

this.responseText = "";



do {

this.readyStateChange(FakeXDomainRequest.LOADING);

this.responseText += body.substring(index, index + chunkSize);

index += chunkSize;

} while (index < body.length);



this.readyStateChange(FakeXDomainRequest.DONE);

}、



respond: function respond(status, contentType, body) {

// content-type ignored, since XDomainRequest does not carry this

// we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease

// test integration across browsers

this.status = typeof status === «number»? status: 200;

this.setResponseBody(body || "");

}、



simulatetimeout: function simulatetimeout() {

this.status = 0;

this.isTimeout = true;

// Access to this should actually throw an error

this.responseText = undefined;

this.readyStateChange(FakeXDomainRequest.DONE);

}

});



sinon.extend(FakeXDomainRequest, {

UNSENT: 0,

OPENED: 1,

LOADING: 3,

DONE: 4

});



sinon.useFakeXDomainRequest = function useFakeXDomainRequest() {

sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {

if (xdr.supportsXDR) {

global.XDomainRequest = xdr.GlobalXDomainRequest;

}



delete sinon.FakeXDomainRequest.restore;



if (keepOnCreate !== true) {

delete sinon.FakeXDomainRequest.onCreate;

}

};

if (xdr.supportsXDR) {

global.XDomainRequest = sinon.FakeXDomainRequest;

}

return sinon.FakeXDomainRequest;

};



sinon.FakeXDomainRequest = FakeXDomainRequest;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./core");

require("../extend");

require("./event");

require("../log_error");

makeApi(sinon);

module.exports = sinon;

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require, module.exports, module);

} else {

makeApi(sinon); // eslint-disable-line no-undef

}

})(typeof global !== «undefined»? global: self);



/**

* depend core.js

* depend ../extend.js

* depend event.js

* depend ../log_error.js

* /

/**

* Fake XMLHttpRequest object

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal, global) {



function getWorkingXHR(globalScope) {

var supportsXHR = typeof globalScope.XMLHttpRequest !== «undefined»;

if (supportsXHR) {

return globalScope.XMLHttpRequest;

}



var supportsActiveX = typeof globalScope.ActiveXObject !== «undefined»;

if (supportsActiveX) {

return function () {

return new globalScope.ActiveXObject(«MSXML2.XMLHTTP.3.0»);

};

}



falseを返します。

}



var supportsProgress = typeof ProgressEvent !== «undefined»;

var supportsCustomEvent = typeof CustomEvent !== «undefined»;

var supportsFormData = typeof FormData !== «undefined»;

var supportsArrayBuffer = typeof ArrayBuffer !== «undefined»;

var supportsBlob = typeof Blob === «function»;

var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest };

sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest;

sinonXhr.GlobalActiveXObject = global.ActiveXObject;

sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== «undefined»;

sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== «undefined»;

sinonXhr.workingXHR = getWorkingXHR(global);

sinonXhr.supportsCORS = sinonXhr.supportsXHR && «withCredentials» in (new sinonXhr.GlobalXMLHttpRequest());



var unsafeHeaders = {

«Accept-Charset»: true,

«Accept-Encoding»: true,

Connection: true,

«Content-Length»: true,

Cookie: true,

Cookie2: true,

«Content-Transfer-Encoding»: true,

Date: true,

Expect: true,

Host: true,

«Keep-Alive»: true,

Referer: true,

TE: true,

Trailer: true,

«Transfer-Encoding»: true,

Upgrade: true,

«User-Agent»: true,

Via: true

};



// An upload object is created for each

// FakeXMLHttpRequest and allows upload

// events to be simulated using uploadProgress

// and uploadError.

function UploadProgress() {

this.eventListeners = {

progress: [],

load: [],

abort: [],

error: []

};

}



UploadProgress.prototype.addEventListener = function addEventListener(event, listener) {

this.eventListeners[event].push(listener);

};



UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) {

var listeners = this.eventListeners[event] || [];



for (var i = 0, l = listeners.length; i < l; ++i) {

if (listeners[i] === listener) {

return listeners.splice(i, 1);

}

}

};



UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) {

var listeners = this.eventListeners[event.type] || [];



for (var i = 0, listener; (listener = listeners[i]) != null; i++) {

listener(event);

}

};



// Note that for FakeXMLHttpRequest to work pre ES5

// we lose some of the alignment with the spec.

// To ensure as close a match as possible,

// set responseType before calling open, send or respond;

function FakeXMLHttpRequest() {

this.readyState = FakeXMLHttpRequest.UNSENT;

this.requestHeaders = {};

this.requestBody = null;

this.status = 0;

this.statusText = "";

this.upload = new UploadProgress();

this.responseType = "";

this.response = "";

if (sinonXhr.supportsCORS) {

this.withCredentials = false;

}



var xhr = this;

var events = [«loadstart», «load», «abort», «loadend»];



function addEventListener(eventName) {

xhr.addEventListener(eventName, function (event) {

var listener = xhr[«on» + eventName];



if (listener && typeof listener === «function») {

listener.call(this, event);

}

});

}



for (var i = events.length — 1; i >= 0; i--) {

addEventListener(events[i]);

}



if (typeof FakeXMLHttpRequest.onCreate === «function») {

FakeXMLHttpRequest.onCreate(this);

}

}



function verifyState(xhr) {

if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {

throw new Error(«INVALID_STATE_ERR»);

}



if (xhr.sendFlag) {

throw new Error(«INVALID_STATE_ERR»);

}

}



function getHeader(headers, header) {

header = header.toLowerCase();



for (var h in headers) {

if (h.toLowerCase() === header) {

return h;

}

}



return null;

}



// filtering to enable a white-list version of Sinon FakeXhr,

// where whitelisted requests are passed through to real XHR

function each(collection, callback) {

if (!collection) {

帰る

}



for (var i = 0, l = collection.length; i < l; i += 1) {

callback(collection[i]);

}

}

function some(collection, callback) {

for (var index = 0; index < collection.length; index++) {

if (callback(collection[index]) === true) {

return true;

}

}

falseを返します。

}

// largest arity in XHR is 5 — XHR#open

var apply = function (obj, method, args) {

switch (args.length) {

case 0: return obj[method]();

case 1: return obj[method](args[0]);

case 2: return obj[method](args[0], args[1]);

case 3: return obj[method](args[0], args[1], args[2]);

case 4: return obj[method](args[0], args[1], args[2], args[3]);

case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]);

}

};



FakeXMLHttpRequest.filters = [];

FakeXMLHttpRequest.addFilter = function addFilter(fn) {

this.filters.push(fn);

};

var IE6Re = /MSIE 6/;

FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {

var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap



each([

«open»,

«setRequestHeader»,

«send»,

«abort»,

«getResponseHeader»,

«getAllResponseHeaders»,

«addEventListener»,

«overrideMimeType»,

«removeEventListener»

], function (method) {

fakeXhr[method] = function () {

return apply(xhr, method, arguments);

};

});



var copyAttrs = function (args) {

each(args, function (attr) {

{

fakeXhr[attr] = xhr[attr];

} catch (e) {

if (!IE6Re.test(navigator.userAgent)) {

throw e;

}

}

});

};



var stateChange = function stateChange() {

fakeXhr.readyState = xhr.readyState;

if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {

copyAttrs([«status», «statusText»]);

}

if (xhr.readyState >= FakeXMLHttpRequest.LOADING) {

copyAttrs([«responseText», «response»]);

}

if (xhr.readyState === FakeXMLHttpRequest.DONE) {

copyAttrs([«responseXML»]);

}

if (fakeXhr.onreadystatechange) {

fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });

}

};



if (xhr.addEventListener) {

for (var event in fakeXhr.eventListeners) {

if (fakeXhr.eventListeners.hasOwnProperty(event)) {



/*eslint-disable no-loop-func*/

each(fakeXhr.eventListeners[event], function (handler) {

xhr.addEventListener(event, handler);

});

/*eslint-enable no-loop-func*/

}

}

xhr.addEventListener(«readystatechange», stateChange);

} else {

xhr.onreadystatechange = stateChange;

}

apply(xhr, «open», xhrArgs);

};

FakeXMLHttpRequest.useFilters = false;



function verifyRequestOpened(xhr) {

if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {

throw new Error(«INVALID_STATE_ERR — » + xhr.readyState);

}

}



function verifyRequestSent(xhr) {

if (xhr.readyState === FakeXMLHttpRequest.DONE) {

throw new Error(«Request done»);

}

}



function verifyHeadersReceived(xhr) {

if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) {

throw new Error(«No headers received»);

}

}



function verifyResponseBodyType(body) {

if (typeof body !== «string») {

var error = new Error(«Attempted to respond to fake XMLHttpRequest with » +

body + ", which is not a string.");

error.name = «InvalidBodyException»;

throw error;

}

}



function convertToArrayBuffer(body) {

var buffer = new ArrayBuffer(body.length);

var view = new Uint8Array(buffer);

for (var i = 0; i < body.length; i++) {

var charCode = body.charCodeAt(i);

if (charCode >= 256) {

throw new TypeError(«arraybuffer or blob responseTypes require binary string, » +

«invalid character » + body[i] + " found.");

}

view[i] = charCode;

}

return buffer;

}



function isXmlContentType(contentType) {

return !contentType || /(text\/xml)|(application\/xml)|(\+xml)/.test(contentType);

}



function convertResponseBody(responseType, contentType, body) {

if (responseType === "" || responseType === «text») {

return body;

} else if (supportsArrayBuffer && responseType === «arraybuffer») {

return convertToArrayBuffer(body);

} else if (responseType === «json») {

{

return JSON.parse(body);

} catch (e) {

// Return parsing failure as null

return null;

}

} else if (supportsBlob && responseType === «blob») {

var blobOptions = {};

if (contentType) {

blobOptions.type = contentType;

}

return new Blob([convertToArrayBuffer(body)], blobOptions);

} else if (responseType === «document») {

if (isXmlContentType(contentType)) {

return FakeXMLHttpRequest.parseXML(body);

}

return null;

}

throw new Error(«Invalid responseType » + responseType);

}



function clearResponse(xhr) {

if (xhr.responseType === "" || xhr.responseType === «text») {

xhr.response = xhr.responseText = "";

} else {

xhr.response = xhr.responseText = null;

}

xhr.responseXML = null;

}



FakeXMLHttpRequest.parseXML = function parseXML(text) {

// Treat empty string as parsing failure

if (text !== "") {

{

if (typeof DOMParser !== «undefined») {

var parser = new DOMParser();

return parser.parseFromString(text, «text/xml»);

}

var xmlDoc = new window.ActiveXObject(«Microsoft.XMLDOM»);

xmlDoc.async = «false»;

xmlDoc.loadXML(text);

return xmlDoc;

} catch (e) {

// Unable to parse XML — no biggie

}

}



return null;

};



FakeXMLHttpRequest.statusCodes = {

100: «Continue»,

101: «Switching Protocols»,

200: «OK»,

201: «Created»,

202: «Accepted»,

203: «Non-Authoritative Information»,

204: «No Content»,

205: «Reset Content»,

206: «Partial Content»,

207: «Multi-Status»,

300: «Multiple Choice»,

301: «Moved Permanently»,

302: «Found»,

303: «See Other»,

304: «Not Modified»,

305: «Use Proxy»,

307: «Temporary Redirect»,

400: «Bad Request»,

401: «Unauthorized»,

402: «Payment Required»,

403: «Forbidden»,

404: «Not Found»,

405: «Method Not Allowed»,

406: «Not Acceptable»,

407: «Proxy Authentication Required»,

408: «Request Timeout»,

409: «Conflict»,

410: «Gone»,

411: «Length Required»,

412: «Precondition Failed»,

413: «Request Entity Too Large»,

414: «Request-URI Too Long»,

415: «Unsupported Media Type»,

416: «Requested Range Not Satisfiable»,

417: «Expectation Failed»,

422: «Unprocessable Entity»,

500: «Internal Server Error»,

501: «Not Implemented»,

502: «Bad Gateway»,

503: «Service Unavailable»,

504: «Gateway Timeout»,

505: «HTTP Version Not Supported»

};



function makeApi(sinon) {

sinon.xhr = sinonXhr;



sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {

async: true,



open: function open(method, url, async, username, password) {

this.method = method;

this.url = url;

this.async = typeof async === «boolean»? async: true;

this.username = username;

this.password = password;

clearResponse(this);

this.requestHeaders = {};

this.sendFlag = false;



if (FakeXMLHttpRequest.useFilters === true) {

var xhrArgs = arguments;

var defake = some(FakeXMLHttpRequest.filters, function (filter) {

return filter.apply(this, xhrArgs);

});

if (defake) {

return FakeXMLHttpRequest.defake(this, arguments);

}

}

this.readyStateChange(FakeXMLHttpRequest.OPENED);

}、



readyStateChange: function readyStateChange(state) {

this.readyState = state;



var readyStateChangeEvent = new sinon.Event(«readystatechange», false, false, this);



if (typeof this.onreadystatechange === «function») {

{

this.onreadystatechange(readyStateChangeEvent);

} catch (e) {

sinon.logError(«Fake XHR onreadystatechange handler», e);

}

}



switch (this.readyState) {

case FakeXMLHttpRequest.DONE:

if (supportsProgress) {

this.upload.dispatchEvent(new sinon.ProgressEvent(«progress», {loaded: 100, total: 100}));

this.dispatchEvent(new sinon.ProgressEvent(«progress», {loaded: 100, total: 100}));

}

this.upload.dispatchEvent(new sinon.Event(«load», false, false, this));

this.dispatchEvent(new sinon.Event(«load», false, false, this));

this.dispatchEvent(new sinon.Event(«loadend», false, false, this));

休憩;

}



this.dispatchEvent(readyStateChangeEvent);

}、



setRequestHeader: function setRequestHeader(header, value) {

verifyState(this);



if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {

throw new Error(«Refused to set unsafe header \»" + header + "\"");

}



if (this.requestHeaders[header]) {

this.requestHeaders[header] += "," + value;

} else {

this.requestHeaders[header] = value;

}

}、



// Helps testing

setResponseHeaders: function setResponseHeaders(headers) {

verifyRequestOpened(this);

this.responseHeaders = {};



for (var header in headers) {

if (headers.hasOwnProperty(header)) {

this.responseHeaders[header] = headers[header];

}

}



if (this.async) {

this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);

} else {

this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;

}

}、



// Currently treats ALL data as a DOMString (ie no Document)

send: function send(data) {

verifyState(this);



if (!/^(get|head)$/i.test(this.method)) {

var contentType = getHeader(this.requestHeaders, «Content-Type»);

if (this.requestHeaders[contentType]) {

var value = this.requestHeaders[contentType].split(";");

this.requestHeaders[contentType] = value[0] + ";charset=utf-8";

} else if (supportsFormData && !(data instanceof FormData)) {

this.requestHeaders[«Content-Type»] = «text/plain;charset=utf-8»;

}



this.requestBody = data;

}



this.errorFlag = false;

this.sendFlag = this.async;

clearResponse(this);

this.readyStateChange(FakeXMLHttpRequest.OPENED);



if (typeof this.onSend === «function») {

this.onSend(this);

}



this.dispatchEvent(new sinon.Event(«loadstart», false, false, this));

}、



abort: function abort() {

this.aborted = true;

clearResponse(this);

this.errorFlag = true;

this.requestHeaders = {};

this.responseHeaders = {};



if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) {

this.readyStateChange(FakeXMLHttpRequest.DONE);

this.sendFlag = false;

}



this.readyState = FakeXMLHttpRequest.UNSENT;



this.dispatchEvent(new sinon.Event(«abort», false, false, this));



this.upload.dispatchEvent(new sinon.Event(«abort», false, false, this));



if (typeof this.onerror === «function») {

this.onerror();

}

}、



getResponseHeader: function getResponseHeader(header) {

if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {

return null;

}



if (/^Set-Cookie2?$/i.test(header)) {

return null;

}



header = getHeader(this.responseHeaders, header);



return this.responseHeaders[header] || null;

}、



getAllResponseHeaders: function getAllResponseHeaders() {

if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {

return "";

}



var headers = "";



for (var header in this.responseHeaders) {

if (this.responseHeaders.hasOwnProperty(header) &&

!/^Set-Cookie2?$/i.test(header)) {

headers += header + ": " + this.responseHeaders[header] + "\r\n";

}

}



return headers;

}、



setResponseBody: function setResponseBody(body) {

verifyRequestSent(this);

verifyHeadersReceived(this);

verifyResponseBodyType(body);

var contentType = this.getResponseHeader(«Content-Type»);



var isTextResponse = this.responseType === "" || this.responseType === «text»;

clearResponse(this);

if (this.async) {

var chunkSize = this.chunkSize || 10;

var index = 0;



do {

this.readyStateChange(FakeXMLHttpRequest.LOADING);



if (isTextResponse) {

this.responseText = this.response += body.substring(index, index + chunkSize);

}

index += chunkSize;

} while (index < body.length);

}



this.response = convertResponseBody(this.responseType, contentType, body);

if (isTextResponse) {

this.responseText = this.response;

}



if (this.responseType === «document») {

this.responseXML = this.response;

} else if (this.responseType === "" && isXmlContentType(contentType)) {

this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);

}

this.readyStateChange(FakeXMLHttpRequest.DONE);

}、



respond: function respond(status, headers, body) {

this.status = typeof status === «number»? status: 200;

this.statusText = FakeXMLHttpRequest.statusCodes[this.status];

this.setResponseHeaders(headers || {});

this.setResponseBody(body || "");

}、



uploadProgress: function uploadProgress(progressEventRaw) {

if (supportsProgress) {

this.upload.dispatchEvent(new sinon.ProgressEvent(«progress», progressEventRaw));

}

}、



downloadProgress: function downloadProgress(progressEventRaw) {

if (supportsProgress) {

this.dispatchEvent(new sinon.ProgressEvent(«progress», progressEventRaw));

}

}、



uploadError: function uploadError(error) {

if (supportsCustomEvent) {

this.upload.dispatchEvent(new sinon.CustomEvent(«error», {detail: error}));

}

}

});



sinon.extend(FakeXMLHttpRequest, {

UNSENT: 0,

OPENED: 1,

HEADERS_RECEIVED: 2,

LOADING: 3,

DONE: 4

});



sinon.useFakeXMLHttpRequest = function () {

FakeXMLHttpRequest.restore = function restore(keepOnCreate) {

if (sinonXhr.supportsXHR) {

global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest;

}



if (sinonXhr.supportsActiveX) {

global.ActiveXObject = sinonXhr.GlobalActiveXObject;

}



delete FakeXMLHttpRequest.restore;



if (keepOnCreate !== true) {

delete FakeXMLHttpRequest.onCreate;

}

};

if (sinonXhr.supportsXHR) {

global.XMLHttpRequest = FakeXMLHttpRequest;

}



if (sinonXhr.supportsActiveX) {

global.ActiveXObject = function ActiveXObject(objId) {

if (objId === «Microsoft.XMLHTTP» || /^Msxml2\.XMLHTTP/i.test(objId)) {



return new FakeXMLHttpRequest();

}



return new sinonXhr.GlobalActiveXObject(objId);

};

}



return FakeXMLHttpRequest;

};



sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./core");

require("../extend");

require("./event");

require("../log_error");

makeApi(sinon);

module.exports = sinon;

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon, // eslint-disable-line no-undef

typeof global !== «undefined»? global: self

));



/**

* depend fake_xdomain_request.js

* depend fake_xml_http_request.js

* depend ../format.js

* depend ../log_error.js

* /

/**

* The Sinon «server» mimics a web server that receives requests from

* sinon.FakeXMLHttpRequest and provides an API to respond to those requests,

* both synchronously and asynchronously. To respond synchronuously, canned

* answers have to be provided upfront.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function () {



var push = [].push;



function responseArray(handler) {

var response = handler;



if (Object.prototype.toString.call(handler) !== "[object Array]") {

response = [200, {}, handler];

}



if (typeof response[2] !== «string») {

throw new TypeError(«Fake server response body should be string, but was » +

typeof response[2]);

}



return response;

}



var wloc = typeof window !== «undefined»? window.location: {};

var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);



function matchOne(response, reqMethod, reqUrl) {

var rmeth = response.method;

var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase();

var url = response.url;

var matchUrl = !url || url === reqUrl || (typeof url.test === «function» && url.test(reqUrl));



return matchMethod && matchUrl;

}



function match(response, request) {

var requestUrl = request.url;



if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {

requestUrl = requestUrl.replace(rCurrLoc, "");

}



if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {

if (typeof response.response === «function») {

var ru = response.url;

var args = [request].concat(ru && typeof ru.exec === «function»? ru.exec(requestUrl).slice(1): []);

return response.response.apply(response, args);

}



return true;

}



falseを返します。

}



function makeApi(sinon) {

sinon.fakeServer = {

create: function (config) {

var server = sinon.create(this);

server.configure(config);

if (!sinon.xhr.supportsCORS) {

this.xhr = sinon.useFakeXDomainRequest();

} else {

this.xhr = sinon.useFakeXMLHttpRequest();

}

server.requests = [];



this.xhr.onCreate = function (xhrObj) {

server.addRequest(xhrObj);

};



return server;

}、

configure: function (config) {

var whitelist = {

«autoRespond»: true,

«autoRespondAfter»: true,

«respondImmediately»: true,

«fakeHTTPMethods»: true

};

var setting;



config = config || {};

for (setting in config) {

if (whitelist.hasOwnProperty(setting) && config.hasOwnProperty(setting)) {

this[setting] = config[setting];

}

}

}、

addRequest: function addRequest(xhrObj) {

var server = this;

push.call(this.requests, xhrObj);



xhrObj.onSend = function () {

server.handleRequest(this);



if (server.respondImmediately) {

server.respond();

} else if (server.autoRespond && !server.responding) {

setTimeout(function () {

server.responding = false;

server.respond();

}, server.autoRespondAfter || 10);



server.responding = true;

}

};

}、



getHTTPMethod: function getHTTPMethod(request) {

if (this.fakeHTTPMethods && /post/i.test(request.method)) {

var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);

return matches? matches[1]: request.method;

}



return request.method;

}、



handleRequest: function handleRequest(xhr) {

if (xhr.async) {

if (!this.queue) {

this.queue = [];

}



push.call(this.queue, xhr);

} else {

this.processRequest(xhr);

}

}、



log: function log(response, request) {

var str;



str = «Request:\n» + sinon.format(request) + "\n\n";

str += «Response:\n» + sinon.format(response) + "\n\n";



sinon.log(str);

}、



respondWith: function respondWith(method, url, body) {

if (arguments.length === 1 && typeof method !== «function») {

this.response = responseArray(method);

帰る

}



if (!this.responses) {

this.responses = [];

}



if (arguments.length === 1) {

body = method;

url = method = null;

}



if (arguments.length === 2) {

body = url;

url = method;

method = null;

}



push.call(this.responses, {

method: method,

url: url,

response: typeof body === «function»? body: responseArray(body)

});

}、



respond: function respond() {

if (arguments.length > 0) {

this.respondWith.apply(this, arguments);

}



var queue = this.queue || [];

var requests = queue.splice(0, queue.length);



for (var i = 0; i < requests.length; i++) {

this.processRequest(requests[i]);

}

}、



processRequest: function processRequest(request) {

{

if (request.aborted) {

帰る

}



var response = this.response || [404, {}, ""];



if (this.responses) {

for (var l = this.responses.length, i = l — 1; i >= 0; i--) {

if (match.call(this, this.responses[i], request)) {

response = this.responses[i].response;

休憩;

}

}

}



if (request.readyState !== 4) {

this.log(response, request);



request.respond(response[0], response[1], response[2]);

}

} catch (e) {

sinon.logError(«Fake server request processing», e);

}

}、



restore: function restore() {

return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);

}

};

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./core");

require("./fake_xdomain_request");

require("./fake_xml_http_request");

require("../format");

makeApi(sinon);

module.exports = sinon;

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require, module.exports, module);

} else {

makeApi(sinon); // eslint-disable-line no-undef

}

}());



/**

* depend fake_server.js

* depend fake_timers.js

* /

/**

* Add-on for sinon.fakeServer that automatically handles a fake timer along with

* the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery

* 1.3.x, which does not use xhr object's onreadystatehandler at all — instead,

* it polls the object for completion with setInterval. Dispite the direct

* motivation, there is nothing jQuery-specific in this file, so it can be used

* in any environment where the ajax implementation depends on setInterval or

* setTimeout.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function () {



function makeApi(sinon) {

function Server() {}

Server.prototype = sinon.fakeServer;



sinon.fakeServerWithClock = new Server();



sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {

if (xhr.async) {

if (typeof setTimeout.clock === «object») {

this.clock = setTimeout.clock;

} else {

this.clock = sinon.useFakeTimers();

this.resetClock = true;

}



if (!this.longestTimeout) {

var clockSetTimeout = this.clock.setTimeout;

var clockSetInterval = this.clock.setInterval;

var server = this;



this.clock.setTimeout = function (fn, timeout) {

server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);



return clockSetTimeout.apply(this, arguments);

};



this.clock.setInterval = function (fn, timeout) {

server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);



return clockSetInterval.apply(this, arguments);

};

}

}



return sinon.fakeServer.addRequest.call(this, xhr);

};



sinon.fakeServerWithClock.respond = function respond() {

var returnVal = sinon.fakeServer.respond.apply(this, arguments);



if (this.clock) {

this.clock.tick(this.longestTimeout || 0);

this.longestTimeout = 0;



if (this.resetClock) {

this.clock.restore();

this.resetClock = false;

}

}



return returnVal;

};



sinon.fakeServerWithClock.restore = function restore() {

if (this.clock) {

this.clock.restore();

}



return sinon.fakeServer.restore.apply(this, arguments);

};

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require) {

var sinon = require("./core");

require("./fake_server");

require("./fake_timers");

makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require);

} else {

makeApi(sinon); // eslint-disable-line no-undef

}

}());



/**

* depend util/core.js

* depend extend.js

* depend collection.js

* depend util/fake_timers.js

* depend util/fake_server_with_clock.js

* /

/**

* Manages fake collections as well as fake utilities such as Sinon's

* timers and fake XHR implementation in one convenient object.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

var push = [].push;



function exposeValue(sandbox, config, key, value) {

if (!value) {

帰る

}



if (config.injectInto && !(key in config.injectInto)) {

config.injectInto[key] = value;

sandbox.injectedKeys.push(key);

} else {

push.call(sandbox.args, value);

}

}



function prepareSandboxFromConfig(config) {

var sandbox = sinon.create(sinon.sandbox);



if (config.useFakeServer) {

if (typeof config.useFakeServer === «object») {

sandbox.serverPrototype = config.useFakeServer;

}



sandbox.useFakeServer();

}



if (config.useFakeTimers) {

if (typeof config.useFakeTimers === «object») {

sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);

} else {

sandbox.useFakeTimers();

}

}



return sandbox;

}



sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {

useFakeTimers: function useFakeTimers() {

this.clock = sinon.useFakeTimers.apply(sinon, arguments);



return this.add(this.clock);

}、



serverPrototype: sinon.fakeServer,



useFakeServer: function useFakeServer() {

var proto = this.serverPrototype || sinon.fakeServer;



if (!proto || !proto.create) {

return null;

}



this.server = proto.create();

return this.add(this.server);

}、



inject: function (obj) {

sinon.collection.inject.call(this, obj);



if (this.clock) {

obj.clock = this.clock;

}



if (this.server) {

obj.server = this.server;

obj.requests = this.server.requests;

}



obj.match = sinon.match;



return obj;

}、



restore: function () {

sinon.collection.restore.apply(this, arguments);

this.restoreContext();

}、



restoreContext: function () {

if (this.injectedKeys) {

for (var i = 0, j = this.injectedKeys.length; i < j; i++) {

delete this.injectInto[this.injectedKeys[i]];

}

this.injectedKeys = [];

}

}、



create: function (config) {

if (!config) {

return sinon.create(sinon.sandbox);

}



var sandbox = prepareSandboxFromConfig(config);

sandbox.args = sandbox.args || [];

sandbox.injectedKeys = [];

sandbox.injectInto = config.injectInto;

var prop,

value;

var exposed = sandbox.inject({});



if (config.properties) {

for (var i = 0, l = config.properties.length; i < l; i++) {

prop = config.properties[i];

value = exposed[prop] || prop === «sandbox» && sandbox;

exposeValue(sandbox, config, prop, value);

}

} else {

exposeValue(sandbox, config, «sandbox», value);

}



return sandbox;

}、



match: sinon.match

});



sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;



return sinon.sandbox;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./extend");

require("./util/fake_server_with_clock");

require("./util/fake_timers");

require("./collection");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend util/core.js

* depend sandbox.js

* /

/**

* Test function, sandboxes fakes

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function makeApi(sinon) {

var slice = Array.prototype.slice;



function test(callback) {

var type = typeof callback;



if (type !== «function») {

throw new TypeError(«sinon.test needs to wrap a test function, got » + type);

}



function sinonSandboxedTest() {

var config = sinon.getConfig(sinon.config);

config.injectInto = config.injectIntoThis && this || config.injectInto;

var sandbox = sinon.sandbox.create(config);

var args = slice.call(arguments);

var oldDone = args.length && args[args.length — 1];

var exception, result;



if (typeof oldDone === «function») {

args[args.length — 1] = function sinonDone(res) {

if (res) {

sandbox.restore();

} else {

sandbox.verifyAndRestore();

}

oldDone(res);

};

}



{

result = callback.apply(this, args.concat(sandbox.args));

} catch (e) {

exception = e;

}



if (typeof oldDone !== «function») {

if (typeof exception !== «undefined») {

sandbox.restore();

throw exception;

} else {

sandbox.verifyAndRestore();

}

}



return result;

}



if (callback.length) {

return function sinonAsyncSandboxedTest(done) { // eslint-disable-line no-unused-vars

return sinonSandboxedTest.apply(this, arguments);

};

}



return sinonSandboxedTest;

}



test.config = {

injectIntoThis: true,

injectInto: null,

properties: [«spy», «stub», «mock», «clock», «server», «requests»],

useFakeTimers: true,

useFakeServer: true

};



sinon.test = test;

return test;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var core = require("./util/core");

require("./sandbox");

module.exports = makeApi(core);

}



if (isAMD) {

define(loadDependencies);

} else if (isNode) {

loadDependencies(require, module.exports, module);

} else if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(typeof sinon === «object» && sinon || null)); // eslint-disable-line no-undef



/**

* depend util/core.js

* depend test.js

* /

/**

* Test case, sandboxes all test functions

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal) {



function createTest(property, setUp, tearDown) {

return function () {

if (setUp) {

setUp.apply(this, arguments);

}



var exception, result;



{

result = property.apply(this, arguments);

} catch (e) {

exception = e;

}



if (tearDown) {

tearDown.apply(this, arguments);

}



if (exception) {

throw exception;

}



return result;

};

}



function makeApi(sinon) {

function testCase(tests, prefix) {

if (!tests || typeof tests !== «object») {

throw new TypeError(«sinon.testCase needs an object with test functions»);

}



prefix = prefix || «test»;

var rPrefix = new RegExp("^" + prefix);

var methods = {};

var setUp = tests.setUp;

var tearDown = tests.tearDown;

var testName,

property,

method;



for (testName in tests) {

if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) {

property = tests[testName];



if (typeof property === «function» && rPrefix.test(testName)) {

method = property;



if (setUp || tearDown) {

method = createTest(property, setUp, tearDown);

}



methods[testName] = sinon.test(method);

} else {

methods[testName] = tests[testName];

}

}

}



return methods;

}



sinon.testCase = testCase;

return testCase;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var core = require("./util/core");

require("./test");

module.exports = makeApi(core);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon // eslint-disable-line no-undef

));



/**

* depend times_in_words.js

* depend util/core.js

* depend match.js

* depend format.js

* /

/**

* Assertions matching the test spy retrieval interface.

*

* author Christian Johansen (christian@cjohansen.no)

* @license BSD

*

* Copyright © 2010-2013 Christian Johansen

* /

(function (sinonGlobal, global) {



var slice = Array.prototype.slice;



function makeApi(sinon) {

var assert;



function verifyIsStub() {

var method;



for (var i = 0, l = arguments.length; i < l; ++i) {

method = arguments[i];



if (!method) {

assert.fail(«fake is not a spy»);

}



if (method.proxy && method.proxy.isSinonProxy) {

verifyIsStub(method.proxy);

} else {

if (typeof method !== «function») {

assert.fail(method + " is not a function");

}



if (typeof method.getCall !== «function») {

assert.fail(method + " is not stubbed");

}

}



}

}



function failAssertion(object, msg) {

object = object || global;

var failMethod = object.fail || assert.fail;

failMethod.call(object, msg);

}



function mirrorPropAsAssertion(name, method, message) {

if (arguments.length === 2) {

message = method;

method = name;

}



assert[name] = function (fake) {

verifyIsStub(fake);



var args = slice.call(arguments, 1);

var failed = false;



if (typeof method === «function») {

failed = !method(fake);

} else {

failed = typeof fake[method] === «function»?

!fake[method].apply(fake, args): !fake[method];

}



if (failed) {

failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args)));

} else {

assert.pass(name);

}

};

}



function exposedName(prefix, prop) {

return !prefix || /^fail/.test(prop)? prop:

prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);

}



assert = {

failException: «AssertError»,



fail: function fail(message) {

var error = new Error(message);

error.name = this.failException || assert.failException;



throw error;

}、



pass: function pass() {},



callOrder: function assertCallOrder() {

verifyIsStub.apply(null, arguments);

var expected = "";

var actual = "";



if (!sinon.calledInOrder(arguments)) {

{

expected = [].join.call(arguments, ", ");

var calls = slice.call(arguments);

var i = calls.length;

while (i) {

if (!calls[--i].called) {

calls.splice(i, 1);

}

}

actual = sinon.orderByFirstCall(calls).join(", ");

} catch (e) {

// If this fails, we'll just fall back to the blank string

}



failAssertion(this, «expected » + expected + " to be " +

«called in order but were called as » + actual);

} else {

assert.pass(«callOrder»);

}

}、



callCount: function assertCallCount(method, count) {

verifyIsStub(method);



if (method.callCount !== count) {

var msg = «expected %n to be called » + sinon.timesInWords(count) +

" but was called %c%C";

failAssertion(this, method.printf(msg));

} else {

assert.pass(«callCount»);

}

}、



expose: function expose(target, options) {

if (!target) {

throw new TypeError(«target is null or undefined»);

}



var o = options || {};

var prefix = typeof o.prefix === «undefined» && «assert» || o.prefix;

var includeFail = typeof o.includeFail === «undefined» || !!o.includeFail;



for (var method in this) {

if (method !== «expose» && (includeFail || !/^(fail)/.test(method))) {

target[exposedName(prefix, method)] = this[method];

}

}



return target;

}、



match: function match(actual, expectation) {

var matcher = sinon.match(expectation);

if (matcher.test(actual)) {

assert.pass(«match»);

} else {

var formatted = [

«expected value to match»,

" expected = " + sinon.format(expectation),

" actual = " + sinon.format(actual)

];



failAssertion(this, formatted.join("\n"));

}

}

};



mirrorPropAsAssertion(«called», «expected %n to have been called at least once but was never called»);

mirrorPropAsAssertion(«notCalled», function (spy) {

return !spy.called;

}, «expected %n to not have been called but was called %c%C»);

mirrorPropAsAssertion(«calledOnce», «expected %n to be called once but was called %c%C»);

mirrorPropAsAssertion(«calledTwice», «expected %n to be called twice but was called %c%C»);

mirrorPropAsAssertion(«calledThrice», «expected %n to be called thrice but was called %c%C»);

mirrorPropAsAssertion(«calledOn», «expected %n to be called with %1 as this but was called with %t»);

mirrorPropAsAssertion(

«alwaysCalledOn»,

«expected %n to always be called with %1 as this but was called with %t»

);

mirrorPropAsAssertion(«calledWithNew», «expected %n to be called with new»);

mirrorPropAsAssertion(«alwaysCalledWithNew», «expected %n to always be called with new»);

mirrorPropAsAssertion(«calledWith», «expected %n to be called with arguments %*%C»);

mirrorPropAsAssertion(«calledWithMatch», «expected %n to be called with match %*%C»);

mirrorPropAsAssertion(«alwaysCalledWith», «expected %n to always be called with arguments %*%C»);

mirrorPropAsAssertion(«alwaysCalledWithMatch», «expected %n to always be called with match %*%C»);

mirrorPropAsAssertion(«calledWithExactly», «expected %n to be called with exact arguments %*%C»);

mirrorPropAsAssertion(«alwaysCalledWithExactly», «expected %n to always be called with exact arguments %*%C»);

mirrorPropAsAssertion(«neverCalledWith», «expected %n to never be called with arguments %*%C»);

mirrorPropAsAssertion(«neverCalledWithMatch», «expected %n to never be called with match %*%C»);

mirrorPropAsAssertion(«threw», "%n did not throw exception%C");

mirrorPropAsAssertion(«alwaysThrew», "%n did not always throw exception%C");



sinon.assert = assert;

return assert;

}



var isNode = typeof module !== «undefined» && module.exports && typeof require === «function»;

var isAMD = typeof define === «function» && typeof define.amd === «object» && define.amd;



function loadDependencies(require, exports, module) {

var sinon = require("./util/core");

require("./match");

require("./format");

module.exports = makeApi(sinon);

}



if (isAMD) {

define(loadDependencies);

帰る

}



if (isNode) {

loadDependencies(require, module.exports, module);

帰る

}



if (sinonGlobal) {

makeApi(sinonGlobal);

}

}(

typeof sinon === «object» && sinon, // eslint-disable-line no-undef

typeof global !== «undefined»? global: self

));



return sinon;

}));





.



All Articles