1  /**
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.env.overload.Overload;
    19  import org.as2lib.env.except.IllegalArgumentException;
    20  import org.as2lib.env.reflect.ProxyFactory;
    21  import org.as2lib.env.reflect.TypeProxyFactory;
    22  import org.as2lib.env.reflect.InvocationHandler;
    23  import org.as2lib.test.mock.ArgumentsMatcher;
    24  import org.as2lib.test.mock.support.DefaultArgumentsMatcher;
    25  import org.as2lib.test.mock.support.TypeArgumentsMatcher;
    26  import org.as2lib.test.mock.Behavior;
    27  import org.as2lib.test.mock.MethodCall;
    28  import org.as2lib.test.mock.MethodCallRange;
    29  import org.as2lib.test.mock.MethodResponse;
    30  import org.as2lib.test.mock.support.DefaultBehavior;
    31  import org.as2lib.test.mock.MockControlState;
    32  import org.as2lib.test.mock.support.RecordState;
    33  import org.as2lib.test.mock.support.ReplayState;
    34  import org.as2lib.test.mock.MockControlStateFactory;
    35  import org.as2lib.env.reflect.ReflectUtil;
    36  
    37  /**
    38   * {@code MockControl} is the central class of the mock object framework. You use
    39   * it to create your mock object, set expectations and verify whether these
    40   * expectations have been met.
    41   *
    42   * <p>The normal workflow is creating a mock control for a specific class or
    43   * interface, receiving the mock object from it, setting expectations, setting the
    44   * behavior of the mock object, switching to replay state, using the mock object as
    45   * if it were a normal instance of a class and verifying that all expectations have
    46   * been met.
    47   * 
    48   * <code>
    49   *   import org.as2lib.test.mock.MockControl;
    50   *
    51   *   // create mock control for class MyClass
    52   *   var myMockControl:MockControl = new MockControl(MyClass);
    53   *   // receive the mock object (it is in record state)
    54   *   var myMock:MyClass = myMockControl.getMock();
    55   *   // expect a call to the setStringProperty-method with argument 'myString'.
    56   *   myMock.setStringProperty("myString");
    57   *   // expect calls to the getStringProperty-method
    58   *   myMock.getStringProperty();
    59   *   // return 'myString' for the first two calls
    60   *   myMockControl.setReturnValue("myString", 2);
    61   *   // throw MyException for any further call
    62   *   myMockControl.setDefaultThrowable(new MyException());
    63   *   // switch to replay state
    64   *   myMockControl.replay();
    65   *
    66   *   // the class under test calls these methods on the mock
    67   *   myMock.setStringProperty("myString");
    68   *   myMock.getStringProperty();
    69   *   myMock.getStringProperty();
    70   *
    71   *   // verify that all expectations have been met
    72   *   myMockControl.verify();
    73   * </code>
    74   *
    75   * <p>If an expectation has not been met an {@link AssertionFailedError} will be
    76   * thrown. If an expectation violation is discovered during execution an
    77   * {@code AssertionFailedError} will be thrown immediately.
    78   * 
    79   * <p>If you had called the {@code setStringProperty} method in the above example
    80   * with another string like {@code "unexpectedString"} an {@code AssertFailedError}
    81   * would have been thrown immediately. If you had called the {@code setStringProperty}
    82   * method a second time, what has not been expected, an {@code AssertionFailedError}
    83   * would also have been thrown immediately. If you had not called the
    84   * {@code setStringProperty} method at all, an {@code AssertionFailedError} would
    85   * have been thrown on verification.
    86   *
    87   * @author Simon Wacker
    88   */
    89  class org.as2lib.test.mock.MockControl extends BasicClass {
    90  	
    91  	/**
    92  	 * Returns a new default arguments matcher.
    93  	 *
    94  	 * @return a new default arguments matcher
    95  	 */
    96  	public static function getDefaultArgumentsMatcher(Void):DefaultArgumentsMatcher {
    97  		return new DefaultArgumentsMatcher();
    98  	}
    99  	
   100  	/**
   101  	 * Returns a new type arguments matcher that is configured with the passed-in
   102  	 * {@code expectedType}.
   103  	 * 
   104  	 * <p>Type arguments matcher matches arguments by type and not by value.
   105  	 *
   106  	 * @return a type arguments matcher
   107  	 */
   108  	public static function getTypeArgumentsMatcher(expectedTypes:Array):TypeArgumentsMatcher {
   109  		return new TypeArgumentsMatcher(expectedTypes);
   110  	}
   111  	
   112  	/** The type of the mock proxy. */
   113  	private var type:Function;
   114  	
   115  	/** Used to create a new mock proxy. */
   116  	private var proxyFactory:ProxyFactory;
   117  	
   118  	/** The created mock proxy. */
   119  	private var mock;
   120  	
   121  	/** The mock behavior. */
   122  	private var behavior:Behavior;
   123  	
   124  	/** The current state. */
   125  	private var state:MockControlState;
   126  	
   127  	/** Factory used to obtain the record state. */
   128  	private var recordStateFactory:MockControlStateFactory;
   129  	
   130  	/** Factory used to obtain the replay state. */
   131  	private var replayStateFactory:MockControlStateFactory;
   132  	
   133  	/** Determines whether to handle {@code toString} method invocations. */
   134  	private var handleToStringInvocations:Boolean;
   135  	
   136  	/**
   137  	 * @overload #MockControlByType
   138  	 * @overload #MockControlByTypeAndBehavior
   139  	 */
   140  	public function MockControl() {
   141  		var o:Overload = new Overload(this);
   142  		o.addHandler([Function], MockControlByType);
   143  		o.addHandler([Function, Behavior], MockControlByTypeAndBehavior);
   144  		o.forward(arguments);
   145  	}
   146  	
   147  	/**
   148  	 * Constrcuts a new {@code MockControl} instance using the default behavior.
   149  	 *
   150  	 * <p>The default behavior is an instance of class {@link org.as2lib.test.mock.support.DefaultBehaviour}.
   151  	 *
   152  	 * <p>This instance is in reset state after creation. That means it is ready to
   153  	 * receive expectations and to record them.
   154  	 *
   155  	 * <p>When you have finished recording you must switch to replay state using the
   156  	 * {@link #replay} method.
   157  	 *
   158  	 * @param type the interface or class to create a mock object for
   159  	 * @throws IllegalArgumentException if the passed-in {@code type} is {@code null}
   160  	 */
   161  	private function MockControlByType(type:Function):Void {
   162  		MockControlByTypeAndBehavior(type, null);
   163  	}
   164  	
   165  	/**
   166  	 * Constructs a new {@code MockControl} instance using the passed-in
   167  	 * {@code bahvior}.
   168  	 *
   169  	 * <p>If the passed-in {@code behavior} is {@code null} the default behavior that
   170  	 * is of type {@link DefaultBehavior} is used instead.
   171  	 *
   172  	 * <p>This instance is in reset state after creation. That means it is ready to
   173  	 * to receive expectations and to record them.
   174  	 *
   175  	 * <p>When you have finished recording you must switch to replay state using the
   176  	 * {@link #replay} method.
   177  	 *
   178  	 * <p>{@code toString} invocations on the mock are by default not handled.
   179  	 *
   180  	 * @param type the interface or class to create a mock object for
   181  	 * @param behavior the instance to store the behavior of the mock
   182  	 * @throws IllegalArgumentException if the passed-in {@code type} is {@code null}
   183  	 * @see #setHandleToStringInvocations
   184  	 */
   185  	private function MockControlByTypeAndBehavior(type:Function, behavior:Behavior):Void {
   186  		if (!type) throw new IllegalArgumentException("The argument type '" + type + "' is not allowed to be null or undefined.");
   187  		this.type = type;
   188  		this.behavior = behavior ? behavior : new DefaultBehavior();
   189  		this.handleToStringInvocations = false;
   190  		reset();
   191  	}
   192  	
   193  	/**
   194  	 * Sets whether to handle {@code toString} invocations on mocks or not.
   195  	 *
   196  	 * <p>Handling {@code toString} invocations means that these invocations are
   197  	 * added to the expected or actual behavior. This means if you set
   198  	 * {@code handleToStringInvocations} to {@code true} calling this method on the
   199  	 * mock in replay state results in an added expection and in record state in a
   200  	 * verification whether the call was expected. If you set it to {@code false} the
   201  	 * result of an invocation of the mock's {@code toString} method is returned.
   202  	 * 
   203  	 * <p>If {@code handleToStringInvocations} is {@code null}, it is interpreted as
   204  	 * {@code false}.
   205  	 *
   206  	 * @param handleToStringInvocations determines whether to handle {@code toStirng}
   207  	 * method invocations
   208  	 */
   209  	public function setHandleToStringInvocations(handleToStringInvocations:Boolean):Void {
   210  		this.handleToStringInvocations = !handleToStringInvocations ? false : true;
   211  	}
   212  	
   213  	/**
   214  	 * Returns whether {@code toString} invocations on the mock are handled.
   215  	 *
   216  	 * <p>Handling {@code toString} invocations means that these invocations are
   217  	 * added to the expected or actual behavior. This means if they are handled,
   218  	 * calling the {@code toString} method on the mock in replay state results in an
   219  	 * added expection and in record state in a verification whether the call was
   220  	 * expected. If they are not handled, the result of an invocation of the mock's
   221  	 * {@code toString} method is returned.
   222  	 *
   223  	 * @return {@code true} if {@code toString} invocations are handled else
   224  	 * {@code false}
   225  	 * @see #setHandleToStringInvocations
   226  	 */
   227  	public function areToStringInvocationsHandled(Void):Boolean {
   228  		return this.handleToStringInvocations;
   229  	}
   230  	
   231  	/**
   232  	 * Returns the currently used mock proxy factory.
   233  	 *
   234  	 * <p>This proxy factoy is either the default {@link TypeProxyFactory} or the one
   235  	 * set via {@code setMockProxyFactory}.
   236  	 *
   237  	 * @return the currently used proxy factory
   238  	 * @see #setMockProxyFactory
   239  	 */
   240  	public function getMockProxyFactory(Void):ProxyFactory {
   241  		if (!proxyFactory) proxyFactory = new TypeProxyFactory();
   242  		return proxyFactory;
   243  	}
   244  	
   245  	/**
   246  	 * Sets the proxy factory used to obtain the mock proxis / mocks.
   247  	 *
   248  	 * <p>If {@code proxyFactory} is {@code null} the {@code getMockProxyFactory}
   249  	 * method will use the default factory.
   250  	 *
   251  	 * @param proxyFactory factory to obtain mock proxies / mocks
   252  	 * @see #getMockProxyFactory
   253  	 */
   254  	public function setMockProxyFactory(proxyFactory:ProxyFactory):Void {
   255  		this.proxyFactory = proxyFactory;
   256  	}
   257  	
   258  	/**
   259  	 * Returns the currently used record state factory.
   260  	 *
   261  	 * <p>This is either the factory set via {@code setRecordStateFactory} or the
   262  	 * default one, which returns instances of the {@link RecordState} class.
   263  	 *
   264  	 * @return the currently used record state factory
   265  	 * @see #setRecordStateFactory
   266  	 */
   267  	public function getRecordStateFactory(Void):MockControlStateFactory {
   268  		if (!recordStateFactory) recordStateFactory = getDefaultRecordStateFactory();
   269  		return recordStateFactory;
   270  	}
   271  	
   272  	/**
   273  	 * Returns the default record state factory.
   274  	 *
   275  	 * <p>The default record state factory returns instances of class
   276  	 * {@link RecordState}.
   277  	 *
   278  	 * @return the default record state factory
   279  	 */
   280  	private function getDefaultRecordStateFactory(Void):MockControlStateFactory {
   281  		var result:MockControlStateFactory = getBlankMockControlStateFactory();
   282  		result.getMockControlState = function(behavior:Behavior):MockControlState {
   283  			return new RecordState(behavior);
   284  		};
   285  		return result;
   286  	}
   287  	
   288  	/**
   289  	 * Sets the new record state factory.
   290  	 *
   291  	 * <p>If {@code recordStateFactory} is {@code null} the default record state
   292  	 * factory gets returned by the {@code getRecordStateFactory} method.
   293  	 *
   294  	 * @param recordStateFactory the new record state factory
   295  	 * @see #getRecordStateFactory
   296  	 */
   297  	public function setRecordStateFactory(recordStateFactory:MockControlStateFactory):Void {
   298  		this.recordStateFactory = recordStateFactory;
   299  	}
   300  	
   301  	/**
   302  	 * Returns the currently used replay state factory.
   303  	 *
   304  	 * <p>This is either the factory set via {@code setReplayStateFactory} or the
   305  	 * default one, which returns instances of the {@link ReplayState} class.
   306  	 *
   307  	 * @return the currently used replay state factory
   308  	 * @see #setReplayStateFactory
   309  	 */
   310  	public function getReplayStateFactory(Void):MockControlStateFactory {
   311  		if (!replayStateFactory) replayStateFactory = getDefaultReplayStateFactory();
   312  		return replayStateFactory;
   313  	}
   314  	
   315  	/**
   316  	 * Returns the default replay state factory.
   317  	 *
   318  	 * <p>The default replay state factory returns instances of class
   319  	 * {@link ReplayState}.
   320  	 *
   321  	 * @return the default replay state factory
   322  	 */
   323  	private function getDefaultReplayStateFactory(Void):MockControlStateFactory {
   324  		var result:MockControlStateFactory = getBlankMockControlStateFactory();
   325  		result.getMockControlState = function(behavior:Behavior):MockControlState {
   326  			return new ReplayState(behavior);
   327  		};
   328  		return result;
   329  	}
   330  	
   331  	/**
   332  	 * Sets the new replay state factory.
   333  	 *
   334  	 * <p>If {@code replayStateFactory} is {@code null} the
   335  	 * {@code getReplayStateFactory} method will return the default replay state
   336  	 * factory.
   337  	 *
   338  	 * @param replayStateFactory the new replay state factory
   339  	 * @see #getReplayStateFactory
   340  	 */
   341  	public function setReplayStateFactory(replayStateFactory:MockControlStateFactory):Void {
   342  		this.replayStateFactory = replayStateFactory;
   343  	}
   344  	
   345  	/**
   346  	 * Returns a blank mock control state factory. That is a factory with no
   347  	 * implemented methods.
   348  	 *
   349  	 * @return a blank mock control state factory
   350  	 */
   351  	private function getBlankMockControlStateFactory(Void):MockControlStateFactory {
   352  		var result = new Object();
   353  		result.__proto__ = MockControlStateFactory["prototype"];
   354  		result.__constructor__ = MockControlStateFactory;
   355  		return result;
   356  	}
   357  	
   358  	/**
   359  	 * Returns the mock object.
   360  	 *
   361  	 * <p>The mock can be casted and typed to the interface or class specified
   362  	 * on instantiation.
   363  	 *
   364  	 * <p>The mock is created using the mock proxy factory returned by the
   365  	 * {@link #getMockProxyFactory} method.
   366  	 *
   367  	 * <p>Once the mock object has been created it is cached. That means this method
   368  	 * always returns the same mock object for this mock control.
   369  	 *
   370  	 * @return the mock object
   371  	 */
   372  	public function getMock(Void) {
   373  		if (!mock) mock = getMockProxyFactory().createProxy(type, createDelegator());
   374  		return mock;
   375  	}
   376  	
   377  	/**
   378  	 * Creates a new invocation handler instance that handles method invocations on
   379  	 * the mock proxy.
   380  	 *
   381  	 * @return a delegator that handles proxy method invocations
   382  	 */
   383  	private function createDelegator(Void):InvocationHandler {
   384  		var result:InvocationHandler = getBlankInvocationHandler();
   385  		var owner:MockControl = this;
   386  		result.invoke = function(proxy, method:String, args:Array) {
   387  			// 'toString' must be excluded because it is used everytime output is made.
   388  			// For example in the success and failure messages of the unit testing api.
   389  			if (method == "toString" && !owner.areToStringInvocationsHandled()) {
   390  				// TODO: Source out into own stringifier class (MockStringifier)
   391  				return "[mock " + ReflectUtil.getTypeNameForInstance(owner.getMock()) + "]";
   392  				//return owner.getMock().__proto__.toString.apply(owner.getMock());
   393  			}
   394  			// calling private methods from an inner anonymous method is not allowed by MTASC
   395  			return owner["invokeMethod"](method, args);
   396  		};
   397  		return result;
   398  	}
   399  	
   400  	/**
   401  	 * Returns a blank invocation handler. That is a handler with no implemented
   402  	 * methods.
   403  	 *
   404  	 * @return a blank invocation handler
   405  	 */
   406  	private function getBlankInvocationHandler(Void):InvocationHandler {
   407  		var result = new Object();
   408  		result.__proto__ = InvocationHandler["prototype"];
   409  		result.__constructor__ = InvocationHandler;
   410  		return result;
   411  	}
   412  	
   413  	/**
   414  	 * Is called when a method is invoked on the proxy.
   415  	 *
   416  	 * @param methodName the name of the invoked method
   417  	 * @param args the arguments passed to the invoked method
   418  	 */
   419  	private function invokeMethod(methodName:String, args:Array) {
   420  		// resolves bug with algorithms that check the existence of a method before
   421  		// they proceed; this is for example with the AsBroadcaster
   422  		var r:Function = mock.__resolve;
   423  		mock.__resolve = null;
   424  		if (!mock[methodName]) {
   425  			if (state instanceof RecordState) {
   426  				var owner:MockControl = this;
   427  				mock[methodName] = function() {
   428  					if (methodName == "toString" && !owner.areToStringInvocationsHandled()) {
   429  						return owner.getMock().__proto__.toString.apply(owner.getMock());
   430  					}
   431  					// calling private methods out of inner anonymous methods is not allowed with MTASC
   432  					return owner["invokeMethod"](methodName, arguments);
   433  				};
   434  			}
   435  		}
   436  		mock.__resolve = r;
   437  		var result;
   438  		try {
   439  			result = state.invokeMethod(new MethodCall(methodName, args));
   440  		} catch(error:org.as2lib.test.mock.MethodCallRangeError) {
   441  			error.setType(type);
   442  			throw error;
   443  		}
   444  		return result;
   445  	}
   446  	
   447  	/**
   448  	 * Switches the mock object from record state to replay state.
   449  	 *
   450  	 * <p>The mock object is in record state as soon as it gets returned by the
   451  	 * {@link #getMock} method.
   452  	 *
   453  	 * <p>You cannot record expectations in replay state. In replay state you verify
   454  	 * that all your expectations have been met, by using the mock as it were a real
   455  	 * instance.
   456  	 *
   457  	 * <p>If an expectations is not met an {@link AssertionFailedError} is thrown.
   458  	 * This is either done during execution of your test or on verification. Take a
   459  	 * look at the example provided in the class documentation to see when what
   460  	 * {@code AssertFailedError} is thrown.
   461  	 */
   462  	public function replay(Void):Void {
   463  		state = getReplayStateFactory().getMockControlState(behavior);
   464  	}
   465  	
   466  	/**
   467  	 * Resets the mock control and the mock object to the state directly after
   468  	 * creation.
   469  	 *
   470  	 * <p>That means that all previously made expectations will be removed and that
   471  	 * the mock object will be again in record state.
   472  	 */
   473  	public function reset(Void):Void {
   474  		behavior.removeAllBehaviors();
   475  		state = getRecordStateFactory().getMockControlState(behavior);
   476  	}
   477  	
   478  	/**
   479  	 * Sets the arguments matcher that will be used for the last method specified by
   480  	 * a method call.
   481  	 *
   482  	 * @param argumentsMatcher the arguments matcher to use for the specific method
   483  	 * @throws IllegalStateException if this mock control is in replay state
   484  	 */
   485  	public function setArgumentsMatcher(argumentsMatcher:ArgumentsMatcher):Void {
   486  		state.setArgumentsMatcher(argumentsMatcher);
   487  	}
   488  	
   489  	/**
   490  	 * Records that the mock object will by default allow the last method specified
   491  	 * by a method call and will react by returning the provided return value.
   492  	 *
   493  	 * <p>Default means that the method can be called 0 to infinite times without
   494  	 * expectation errors.
   495  	 *
   496  	 * @param value the return value to return
   497  	 * @throws IllegalStateException if this mock control is in replay state
   498  	 */
   499  	public function setDefaultReturnValue(value):Void {
   500  		var response:MethodResponse = new MethodResponse();
   501  		response.setReturnValue(value);
   502  		state.setMethodResponse(response, new MethodCallRange());
   503  	}
   504  	
   505  	/**
   506  	 * Records that the mock object will by default allow the last method specified
   507  	 * by a method call, and will react by throwing the provided throwable.
   508  	 *
   509  	 * <p>Default means that the method can be called zero to infinite times without
   510  	 * expectation errors.
   511  	 *
   512  	 * @param throwable the throwable to throw
   513  	 * @throws IllegalStateException if this mock control is in replay state
   514  	 */
   515  	public function setDefaultThrowable(throwable):Void {
   516  		var response:MethodResponse = new MethodResponse();
   517  		response.setThrowable(throwable);
   518  		state.setMethodResponse(response, new MethodCallRange());
   519  	}
   520  	
   521  	/**
   522  	 * Recards that the mock object will by default allow the last method specified
   523  	 * by a method call.
   524  	 *
   525  	 * <p>Default means that the method can be called zero to infinite times without
   526  	 * expectation errors.
   527  	 *
   528  	 * <p>Calling this method is not necessary. The mock control expects the last
   529  	 * method specified by a method call as soon as this method call occured.
   530  	 *
   531  	 * @throws IllegalStateException if this mock control is in replay state
   532  	 */
   533  	public function setDefaultVoidCallable(Void):Void {
   534  		state.setMethodResponse(new MethodResponse(), new MethodCallRange());
   535  	}
   536  	
   537  	/**
   538  	 * @overload #setReturnValueByValue
   539  	 * @overload #setReturnValueByValueAndQuantity
   540  	 * @overload #setReturnValueByValueAndMinimumAndMaximumQuantity
   541  	 */
   542  	public function setReturnValue():Void {
   543  		var o:Overload = new Overload(this);
   544  		o.addHandler([Object], setReturnValueByValue);
   545  		o.addHandler([Object, Number], setReturnValueByValueAndQuantity);
   546  		o.addHandler([Object, Number, Number], setReturnValueByValueAndMinimumAndMaximumQuantity);
   547  		o.forward(arguments);
   548  	}
   549  	
   550  	/**
   551  	 * Records that the mock object will expect the last method call once and will
   552  	 * react by returning the provided return value.
   553  	 *
   554  	 * @param value the return value to return
   555  	 * @throws IllegalStateException if this mock control is in replay state
   556  	 */
   557  	public function setReturnValueByValue(value):Void {
   558  		setReturnValueByValueAndQuantity(value, 1);
   559  	}
   560  	
   561  	/**
   562  	 * Records that the mock object will expect the last method call a fixed number
   563  	 * of times and will react by returning the provided return value.
   564  	 *
   565  	 * @param value the return value to return
   566  	 * @param quantity the number of times the method is allowed to be invoked
   567  	 * @throws IllegalStateException if this mock control is in replay state
   568  	 */
   569  	public function setReturnValueByValueAndQuantity(value, quantity:Number):Void {
   570  		var response:MethodResponse = new MethodResponse();
   571  		response.setReturnValue(value);
   572  		state.setMethodResponse(response, new MethodCallRange(quantity));
   573  	}
   574  	
   575  	/**
   576  	 * Records that the mock object will expect the last method call between
   577  	 * {@code minimumQuantity} and {@code maximumQuantity} times and will react by
   578  	 * returning the provided return value.
   579  	 *
   580  	 * @param value the return value to return
   581  	 * @param minimumQuantity the minimum number of times the method must be called
   582  	 * @param maximumQuantity the maximum number of times the method can be called
   583  	 * @throws IllegalStateException if this mock control is in replay state
   584  	 */
   585  	public function setReturnValueByValueAndMinimumAndMaximumQuantity(value, minimumQuantity:Number, maximumQuantity:Number):Void {
   586  		var response:MethodResponse = new MethodResponse();
   587  		response.setReturnValue(value);
   588  		state.setMethodResponse(response, new MethodCallRange(minimumQuantity, maximumQuantity));
   589  	}
   590  	
   591  	/**
   592  	 * @overload #setThrowableByThrowable
   593  	 * @overload #setThrowableByThrowableAndQuantity
   594  	 * @overload #setThrowableByThrowableAndMinimumAndMaximumQuantity
   595  	 */
   596  	public function setThrowable():Void {
   597  		var o:Overload = new Overload(this);
   598  		o.addHandler([Object], setThrowableByThrowable);
   599  		o.addHandler([Object, Number], setThrowableByThrowableAndQuantity);
   600  		o.addHandler([Object, Number, Number], setThrowableByThrowableAndMinimumAndMaximumQuantity);
   601  		o.forward(arguments);
   602  	}
   603  	
   604  	/**
   605  	 * Records that the mock object will expect the last method call once and will
   606  	 * react by throwing the provided throwable.
   607  	 *
   608  	 * @param throwable the throwable to throw
   609  	 * @throws IllegalStateException if this mock control is in replay state
   610  	 */
   611  	public function setThrowableByThrowable(throwable):Void {
   612  		setThrowableByThrowableAndQuantity(throwable, 1);
   613  	}
   614  	
   615  	/**
   616  	 * Records that the mock object will expect the last method call a fixed number
   617  	 * of times and will react by throwing the provided throwable.
   618  	 *
   619  	 * @param throwable the throwable to throw
   620  	 * @param quantity the number of times the method is allowed to be invoked
   621  	 * @throws IllegalStateException if this mock control is in replay state
   622  	 */
   623  	public function setThrowableByThrowableAndQuantity(throwable, quantity:Number):Void {
   624  		var response:MethodResponse = new MethodResponse();
   625  		response.setThrowable(throwable);
   626  		state.setMethodResponse(response, new MethodCallRange(quantity));
   627  	}
   628  	
   629  	/**
   630  	 * Records that the mock object will expect the last method call between 
   631  	 * {@code minimumQuantity} and {@code maximumQuantity times} and will react by
   632  	 * throwing the provided throwable.
   633  	 *
   634  	 * @param throwable the throwable to throw
   635  	 * @param minimumQuantity the minimum number of times the method must be called
   636  	 * @param maximumQuantity the maximum number of times the method can be called
   637  	 * @throws IllegalStateException if this mock control is in replay state
   638  	 */
   639  	public function setThrowableByThrowableAndMinimumAndMaximumQuantity(throwable, minimumQuantity:Number, maximumQuantity:Number):Void {
   640  		var response:MethodResponse = new MethodResponse();
   641  		response.setThrowable(throwable);
   642  		state.setMethodResponse(response, new MethodCallRange(minimumQuantity, maximumQuantity));
   643  	}
   644  	
   645  	/**
   646  	 * @overload #setVoidCallableByVoid
   647  	 * @overload #setVoidCallableByQuantity
   648  	 * @overload #setVoidCallableByMinimumAndMaximumQuantity
   649  	 */
   650  	public function setVoidCallable():Void {
   651  		var o:Overload = new Overload(this);
   652  		o.addHandler([], setVoidCallableByVoid);
   653  		o.addHandler([Number], setVoidCallableByQuantity);
   654  		o.addHandler([Number, Number], setVoidCallableByMinimumAndMaximumQuantity);
   655  		o.forward(arguments);
   656  	}
   657  	
   658  	/**
   659  	 * Records that the mock object will expect the last method call once and will
   660  	 * react by returning silently.
   661  	 *
   662  	 * @throws IllegalStateException if this mock control is in replay state
   663  	 */
   664  	public function setVoidCallableByVoid(Void):Void {
   665  		setVoidCallableByQuantity(1);
   666  	}
   667  	
   668  	/**
   669  	 * Records that the mock object will expect the last method call a fixed number
   670  	 * of times and will react by returning silently.
   671  	 *
   672  	 * @param quantity the number of times the method is allowed to be invoked
   673  	 * @throws IllegalStateException if this mock control is in replay state
   674  	 */
   675  	public function setVoidCallableByQuantity(quantity:Number):Void {
   676  		state.setMethodResponse(new MethodResponse(), new MethodCallRange(quantity));
   677  	}
   678  	
   679  	/**
   680  	 * Records that the mock object will expect the last method call between 
   681  	 * {@code minimumQuantity} and {@code maximumQuantity} times and will react by
   682  	 * returning silently.
   683  	 *
   684  	 * @param minimumQuantity the minimum number of times the method must be called
   685  	 * @param maximumQuantity the maximum number of times the method can be called
   686  	 * @throws IllegalStateException if this mock control is in replay state
   687  	 */
   688  	public function setVoidCallableByMinimumAndMaximumQuantity(minimumQuantity:Number, maximumQuantity:Number):Void {
   689  		state.setMethodResponse(new MethodResponse(), new MethodCallRange(minimumQuantity, maximumQuantity));
   690  	}
   691  	
   692  	/**
   693  	 * Verifies that all expectations have been met that could not been verified
   694  	 * during execution.
   695  	 *
   696  	 * @throws IllegalStateException if this mock control is in record state
   697  	 * @throws AssertionFailedError if an expectation has not been met
   698  	 */
   699  	public function verify(Void):Void {
   700  		try {
   701  			state.verify();
   702  		} catch(error:org.as2lib.test.mock.MethodCallRangeError) {
   703  			error.setType(type);
   704  			throw error;
   705  		}
   706  	}
   707  	
   708  }