All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.Invocations Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for developer (unit/integration) testing. It contains mocking APIs and other tools, supporting both JUnit and TestNG. The mocking APIs allow all kinds of Java code, without testability restrictions, to be tested in isolation from selected dependencies.

There is a newer version: 1.7
Show newest version
/*
 * Copyright (c) 2006-2011 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit;

import java.util.regex.*;

import mockit.external.hamcrest.*;
import mockit.external.hamcrest.Matcher;
import mockit.external.hamcrest.core.*;
import mockit.external.hamcrest.number.*;
import mockit.internal.expectations.*;
import mockit.internal.startup.*;
import mockit.internal.util.*;

/**
 * Provides common user API for both the {@linkplain Expectations record} and {@linkplain Verifications verification}
 * phases of a test.
 */
abstract class Invocations
{
   static
   {
      Startup.verifyInitialization();
   }

   /**
    * Matches any {@code Object} reference for the relevant parameter.
    * Note that the use of this field will usually require a cast to the specific parameter type.
    * If there is any other parameter for which an argument matching constraint can be specified, though, the
    * {@code null} reference can be passed instead, as it will also match any reference during the replay phase.
    * 

* Note: in invocations to non-accessible methods or constructors (for example, with * {@link #invoke(Object, String, Object...)}), use {@link #withAny} instead. * * @see #anyInt */ protected static final Object any = null; /** * Matches any {@code String} value for the relevant parameter. * * @see #anyInt */ // This is intentional: the empty string causes the compiler to not generate a field read, // while the null reference is inconvenient with the invoke(...) methods: protected static final String anyString = new String(); /** * Matches any {@code long} or {@code Long} value for the relevant parameter. * * @see #anyInt */ protected static final Long anyLong = 0L; /** * Matches any {@code int} or {@code Integer} value for the relevant parameter. *

* When used as argument for a method/constructor invocation in the recording or verification phase of a test, * specifies the matching of any value passed as argument to corresponding invocations in the replay phase. *

* In the * Tutorial */ protected static final Integer anyInt = 0; /** * Matches any {@code short} or {@code Short} value for the relevant parameter. * * @see #anyInt */ protected static final Short anyShort = 0; /** * Matches any {@code byte} or {@code Byte} value for the relevant parameter. * * @see #anyInt */ protected static final Byte anyByte = 0; /** * Matches any {@code boolean} or {@code Boolean} value for the relevant parameter. * * @see #anyInt */ protected static final Boolean anyBoolean = false; /** * Matches any {@code char} or {@code Character} value for the relevant parameter. * * @see #anyInt */ protected static final Character anyChar = '\0'; /** * Matches any {@code double} or {@code Double} value for the relevant parameter. * * @see #anyInt */ protected static final Double anyDouble = 0.0; /** * Matches any {@code float} or {@code Float} value for the relevant parameter. * * @see #anyInt */ protected static final Float anyFloat = 0.0F; /** * An object assigned to this field will be taken as a handler for each invocation matching the current expectation, * with the purpose of validating invocation arguments. * Note that for a recorded expectation such invocations are the ones that will be executed during the * replay phase, while for a verified expectation they are the ones actually executed during that * phase. *

* The object assigned can be of any type, provided its class has a single non-private method * (therefore, additional methods are allowed and ignored, as long as they are {@code private}). * This handler method can have any name, as long as its parameters match the ones defined in the mocked * method or constructor associated with the expectation. * Corresponding parameters don't need to have the exact same declared type, though, as long as each possible * invocation argument can be passed to the corresponding parameter in the handler method. *

* In the case of an expectation recorded for a non-{@code void} method, the handler method is also responsible for * returning appropriate values to be used by the caller (which normally belongs to the code under test). * That is, the {@code result} field or the {@code returns(...)} method should not be used together with an * assignment to this field. * The same observation applies to the throwing of exceptions/errors from a recorded expectation * (which can also be done for constructors and {@code void} methods). *

* When used for an expectation inside a verification block, on the other hand, the handler method should * normally have a {@code void} return type. Any value eventually returned by the method will be silently ignored in * this case. Note that a handler method for a verified expectation also shouldn't intentionally throw exceptions or * errors, since the verified invocation(s) already happened in the replay phase; any exception/error actually thrown * will simply propagate back to the test method. *

* Just like with {@linkplain mockit.Delegate delegate classes}, the handler method can declare its first parameter * as being of type {@link mockit.Invocation}. *

* In the * Tutorial */ protected static Object forEachInvocation; /** * A non-negative value assigned to this field will be taken as the exact number of times that * invocations matching the current expectation should occur during replay. *

* In the * Tutorial * * @see #minTimes * @see #maxTimes */ protected static int times; /** * A non-negative value assigned to this field will be taken as the minimum number of times that invocations matching * the current expectation should occur during replay. * Zero or a negative value implies there is no lower limit. * The maximum number of times is automatically adjusted to allow any number of invocations. *

* Both {@code minTimes} and {@code maxTimes} can be specified for the same expectation, as long as {@code minTimes} * is assigned first. * * @see #times * @see #maxTimes */ protected static int minTimes; /** * A non-negative value assigned to this field will be taken as the maximum number of times that invocations matching * the current expectation should occur during replay. * A negative value implies there is no upper limit. *

* Both {@code minTimes} and {@code maxTimes} can be specified for the same expectation, as long as {@code minTimes} * is assigned first. * * @see #times * @see #minTimes */ protected static int maxTimes; /** * A value assigned to this field will be used as a prefix for the error message to be reported * if and when the current expectation is violated. *

* Inside an expectation/verification block, the assignment must follow the * invocation which records/verifies the expectation; if there is no current expectation at the * point the assignment appears, an {@code IllegalStateException} is thrown. *

* Notice there are only two different ways in which an expectation can be violated: either an * unexpected invocation occurs, or a missing invocation is detected. */ protected static CharSequence $; Invocations() {} abstract TestOnlyPhase getCurrentPhase(); /** * Specify that the next invocation on the given mocked instance must match a corresponding invocation on the * same instance in the replay phase. *

* By default, such instances can be different between the replay phase and the record or verify phase, even though * the method or constructor invoked is the same, and the invocation arguments all match. * The use of this method allows invocations to also be matched on the instance invoked. *

* Typically, tests that need to match instance invocations on the mocked instances invoked will declare two or more * mock fields and/or parameters of the exact same mocked type. These instances will then be passed to the code under * test, which will invoke them during the replay phase. * To avoid the need to explicitly call {@code onInstance(Object)} on each of these different instances of the * same type, instance matching is implied (and automatically applied to all relevant invocations) whenever * two or more mocked instances of the same type are in scope for a given test method. This property of the API makes * the use of {@code onInstance} much less frequent than it might otherwise be. *

* In most cases, an invocation to the given mocked instance will be made on the value returned by this method (ie, * a chained invocation). * However, in the situation where the tested method calls an instance method defined in a mocked super-class * (possibly an overridden method called through the {@code super} keyword), it will be necessary to match on a * different instance than the one used for recording invocations. * To do so, this method should be given the desired instance to match, while the invocation to be recorded should be * done on the available mocked instance, which must be a different one (otherwise a non-mocked method would get * executed). * This is valid only if the instance to be matched is assignable to the mocked type, and typically occurs when * partially mocking a class hierarchy. *

* In the * Tutorial * * @return the given mocked instance, allowing the invocation to be recorded/verified to immediately follow the call * to this method */ protected final T onInstance(T mockedInstance) { if (mockedInstance == null) { throw new NullPointerException("Missing mocked instance to match"); } getCurrentPhase().setNextInstanceToMatch(mockedInstance); return mockedInstance; } // Methods for argument matching /////////////////////////////////////////////////////////////////////////////////// /** * Adds a custom argument matcher for a parameter in the current invocation. *

* The given matcher can be any existing Hamcrest matcher or a user provided one. * Additionally, it can be an instance of an arbitrary invocation handler class, similar to those used with * the {@link #forEachInvocation} field. * In this case, the non-{@code private} handler method must have a single parameter of a type capable of * receiving the relevant argument values. * The name of this handler method does not matter. Its return type, on the other hand, should either be * {@code boolean} or {@code void}. In the first case, a return value of {@code true} will indicate a successful * match for the actual invocation argument at replay time, while a return of {@code false} will cause the test to * fail. In the second case, instead of returning a value the invocation handler method should validate the actual * invocation argument through an {@code assert} statement or a JUnit/TestNG assertion. *

* For additional details, refer to {@link #withEqual(Object)}. * * @param argValue an arbitrary value of the proper type, necessary to provide a valid argument to the invocation * parameter * @param argumentMatcher an instance of a class implementing the {@code org.hamcrest.Matcher} interface, or any * other instance with an appropriate invocation handler method * * @return the given {@code argValue} */ protected final T with(T argValue, Object argumentMatcher) { addMatcher(HamcrestAdapter.create(argumentMatcher)); return argValue; } /** * Adds a custom argument matcher for a parameter in the current invocation. * This works like {@link #with(Object, Object)}, but attempting to extract the argument value from the supplied * argument matcher. * * @param argumentMatcher an instance of a class implementing the {@code org.hamcrest.Matcher} interface, or any * other instance with an appropriate invocation handler method * * @return the value recorded inside the given argument matcher, or {@code null} if no such value could be determined */ protected final T with(Object argumentMatcher) { HamcrestAdapter adapter = HamcrestAdapter.create(argumentMatcher); addMatcher(adapter); Object argValue = adapter.getInnerValue(); //noinspection unchecked return (T) argValue; } private void addMatcher(Matcher matcher) { getCurrentPhase().addArgMatcher(matcher); } /** * Same as {@link #withEqual(Object)}, but matching any argument value of the appropriate type. *

* Consider using instead the "anyXyz" field appropriate to the parameter type: * {@link #anyBoolean}, {@link #anyByte}, {@link #anyChar}, {@link #anyDouble}, {@link #anyFloat}, {@link #anyInt}, * {@link #anyLong}, {@link #anyShort}, {@link #anyString}, or {@link #any} for other reference types. *

* Note: when using {@link #invoke(Object, String, Object...)}, etc., it's valid to pass * {@code withAny(ParameterType.class)} if an actual instance of the parameter type cannot be created. * * @param arg an arbitrary value which will match any argument value in the replay phase * * @return the input argument */ protected final T withAny(T arg) { addMatcher(new IsAnything()); return arg; } /** * When called as argument for a method/constructor invocation in the recording or verification phase of a test, * creates a new matcher that will check if the given value is {@link Object#equals(Object) equal} to the * corresponding invocation argument in the replay phase. *

* The matcher is added to the end of the list of argument matchers for the invocation being recorded/verified. * It cannot be reused for a different parameter. *

* Usually, this particular method should not be used. Instead, simply pass the desired argument value * directly, without any matcher. * Only when specifying values for a varargs method it's useful, and even then only when some other argument * matcher is also used. *

* In the * Tutorial * * @param arg the expected argument value * * @return the given argument */ protected final T withEqual(T arg) { //noinspection unchecked addMatcher(new IsEqual(arg)); return arg; } /** * Same as {@link #withEqual(Object)}, but checking that a numeric invocation argument in the replay phase is * sufficiently close to the given value. * * @param value the center value for range comparison * @param delta the tolerance around the center value, for a range of [value - delta, value + delta] * * @return the given {@code value} */ protected final double withEqual(double value, double delta) { addMatcher(new IsCloseTo(value, delta)); return value; } /** * Same as {@link #withEqual(Object)}, but checking that a numeric invocation argument in the replay phase is * sufficiently close to the given value. * * @param value the center value for range comparison * @param delta the tolerance around the center value, for a range of [value - delta, value + delta] * * @return the given {@code value} */ protected final float withEqual(float value, double delta) { addMatcher(new IsCloseTo(value, delta)); return value; } /** * Same as {@link #withEqual(Object)}, but checking that an invocation argument in the replay phase is an instance of * the same class as the given object. *

* Equivalent to a withInstanceOf(object.getClass()) call, except that it returns {@code object} instead * of {@code null}. * * @param object an instance of the desired class * * @return the given instance */ protected final T withInstanceLike(T object) { addMatcher(new IsInstanceOf(object.getClass())); return object; } /** * Same as {@link #withEqual(Object)}, but checking that an invocation argument in the replay phase is an instance of * the given class. * * @param argClass the desired class * * @return always {@code null}; if you need a specific return value, use {@link #withInstanceLike(Object)} */ protected final T withInstanceOf(Class argClass) { addMatcher(new IsInstanceOf(argClass)); return null; } /** * Same as {@link #withEqual(Object)}, but checking that the invocation argument in the replay phase is different * from the given value. * * @param arg an arbitrary value, but different from the ones expected to occur during replay * * @return the given argument value */ protected final T withNotEqual(T arg) { //noinspection unchecked addMatcher(new IsNot(new IsEqual(arg))); return arg; } /** * Same as {@link #withEqual(Object)}, but checking that an invocation argument in the replay phase is not * {@code null}. * * @return always {@code null} */ protected final T withNotNull() { addMatcher(new IsNot(new IsNull())); return null; } /** * Same as {@link #withEqual(Object)}, but checking that an invocation argument in the replay phase is {@code null}. * * @return always {@code null} */ protected final T withNull() { addMatcher(new IsNull()); return null; } /** * Same as {@link #withEqual(Object)}, but checking that an invocation argument in the replay phase is the exact same * instance as the one in the recorded/verified invocation. * * @param object the desired instance * @return the given object */ protected final T withSameInstance(T object) { //noinspection unchecked addMatcher(new IsSame(object)); return object; } // Text-related matchers /////////////////////////////////////////////////////////////////////////////////////////// /** * Same as {@link #withEqual(Object)}, but checking that a textual invocation argument in the replay phase contains * the given text as a substring. * * @param text an arbitrary non-null textual value * * @return the given text */ protected final T withSubstring(T text) { addMatcher(new StringContains(text)); return text; } /** * Same as {@link #withEqual(Object)}, but checking that a textual invocation argument in the replay phase starts * with the given text. * * @param text an arbitrary non-null textual value * * @return the given text */ protected final T withPrefix(T text) { addMatcher(new StringStartsWith(text)); return text; } /** * Same as {@link #withEqual(Object)}, but checking that a textual invocation argument in the replay phase ends with * the given text. * * @param text an arbitrary non-null textual value * * @return the given text */ protected final T withSuffix(T text) { addMatcher(new StringEndsWith(text)); return text; } /** * Same as {@link #withEqual(Object)}, but checking that a textual invocation argument in the replay phase matches * the given {@link Pattern regular expression}. *

* Note that this can be used for any string comparison, including case insensitive ones (with {@code "(?i)"} in the * regex). * * @param regex an arbitrary (non-null) regular expression against which textual argument values will be matched * * @return the given regex * * @see Pattern#compile(String, int) */ protected final T withMatch(T regex) { final Pattern pattern = Pattern.compile(regex.toString()); addMatcher(new BaseMatcher() { public boolean matches(Object item) { return pattern.matcher((CharSequence) item).matches(); } public void describeTo(Description description) { description.appendText("a string matching ").appendValue(pattern); } }); return regex; } // Methods for instantiating non-accessible classes //////////////////////////////////////////////////////////////// /** * Specifies an expectation for a constructor of a given class. *

* This is useful for invoking non-accessible constructors ({@code private} ones, for example) from the test, which * otherwise could not be called normally. It should not be used for accessible constructors. *

* In the * Tutorial * * @param className the fully qualified name of the desired class * @param parameterTypes the formal parameter types for the desired constructor, possibly empty * @param initArgs the invocation arguments for the constructor, which must be consistent with the specified * parameter types * @param interface or super-class type to which the returned instance should be assignable * * @return a newly created instance of the specified class, initialized with the specified constructor and arguments * * @see #newInstance(String, Object...) * @see #newInnerInstance(String, Object, Object...) */ protected final T newInstance(String className, Class[] parameterTypes, Object... initArgs) { //noinspection unchecked return (T) Utilities.newInstance(className, parameterTypes, initArgs); } /** * The same as {@link #newInstance(String, Class[], Object...)}, but inferring parameter types from non-null argument * values. * If a given parameter needs to match {@code null} during replay, then the corresponding {@code Class} literal must * be passed instead of {@code null}. * * @param nonNullInitArgs zero or more non-null expected parameter values for the expectation; * if a null value needs to be passed, the {@code Class} object for the parameter type must be passed instead * * @throws IllegalArgumentException if one of the given arguments is {@code null} */ protected final T newInstance(String className, Object... nonNullInitArgs) { //noinspection unchecked return (T) Utilities.newInstance(className, nonNullInitArgs); } /** * The same as {@link #newInstance(String, Class[], Object...)}, but for instantiating an inner non-accessible class * of some other class, and where all other (if any) initialization arguments are known to be non null. * * @param innerClassSimpleName simple name of the inner class, that is, the part after the "$" character in its full * name * @param outerClassInstance the outer class instance to which the inner class instance will belong * @param nonNullInitArgs zero or more non-null expected parameter values for the expectation; * if a null value needs to be passed, the {@code Class} object for the parameter type must be passed instead */ protected final T newInnerInstance( String innerClassSimpleName, Object outerClassInstance, Object... nonNullInitArgs) { //noinspection unchecked return (T) Utilities.newInnerInstance(innerClassSimpleName, outerClassInstance, nonNullInitArgs); } // Methods for invoking non-accessible methods on instances or classes ///////////////////////////////////////////// /** * Specifies an expectation for an instance method, with a given list of arguments. *

* This is useful when a method is not accessible from the test (it's {@code private}, for example), and therefore * cannot be called normally. It should not be used to call accessible methods. *

* Additionally, this can also be used to directly test private methods, when there is no other way to do so, or it * would be too difficult by indirect means. * Note that in such a case the target instance will actually be a "real" (non-mocked) object. *

* In the * Tutorial * * @param objectWithMethod the instance on which the invocation is to be done; must not be null * @param methodName the name of the expected method * @param methodArgs zero or more non-null expected parameter values for the expectation; * if a null value needs to be passed, the {@code Class} object for the parameter type must be passed instead * * @return the return value from the invoked method, wrapped if primitive * * @throws IllegalArgumentException if a null reference was provided for a parameter * * @see #invoke(Class, String, Object...) */ protected final T invoke(Object objectWithMethod, String methodName, Object... methodArgs) { //noinspection unchecked return (T) Utilities.invoke(objectWithMethod.getClass(), objectWithMethod, methodName, methodArgs); } /** * Specifies an expectation for a {@code static} method, with a given list of arguments. *

* This is useful when a method is not accessible from the test (it's {@code private}, for example), and therefore * cannot be called normally. It should not be used to call accessible methods. *

* Additionally, this can also be used to directly test private methods, when there is no other way to do so, or it * would be too difficult by indirect means. * Note that in such a case the target class would not be mocked. * * @param methodOwner the class on which the invocation is to be done; must not be null * @param methodName the name of the expected static method * @param methodArgs zero or more non-null expected parameter values for the expectation; * if a null value needs to be passed, the {@code Class} object for the parameter type must be passed instead * * @return the return value from the invoked method, wrapped if primitive * * @throws IllegalArgumentException if a null reference was provided for a parameter */ protected final T invoke(Class methodOwner, String methodName, Object... methodArgs) { //noinspection unchecked return (T) Utilities.invoke(methodOwner, null, methodName, methodArgs); } // Methods for getting/setting non-accessible fields on instances or classes /////////////////////////////////////// /** * Gets the value of a non-accessible field from a given object. *

* In the * Tutorial * * @param fieldOwner the instance from which to get the field value * @param fieldName the name of the field to get * * @see #setField(Object, String, Object) */ protected final T getField(Object fieldOwner, String fieldName) { //noinspection unchecked return (T) Utilities.getField(fieldOwner.getClass(), fieldName, fieldOwner); } /** * Gets the value of a non-accessible field from a given object, assuming there is only * one field declared in the class of the given object whose type can receive values of the * specified field type. * * @param fieldOwner the instance from which to get the field value * @param fieldType the declared type of the field, or a sub-type of the declared field type * * @see #getField(Object, String) * * @throws IllegalArgumentException if either the desired field is not found, or more than one is */ protected final T getField(Object fieldOwner, Class fieldType) { //noinspection unchecked return Utilities.getField(fieldOwner.getClass(), fieldType, fieldOwner); } /** * Gets the value of a non-accessible static field defined in a given class. * * @param fieldOwner the class from which to get the field value * @param fieldName the name of the static field to get * * @see #setField(Class, String, Object) */ protected final T getField(Class fieldOwner, String fieldName) { //noinspection unchecked return (T) Utilities.getField(fieldOwner, fieldName, null); } /** * Gets the value of a non-accessible static field defined in a given class. * * @param fieldOwner the class from which to get the field value * @param fieldType the declared type of the field, or a sub-type of the declared field type * * @see #setField(Class, String, Object) */ protected final T getField(Class fieldOwner, Class fieldType) { //noinspection unchecked return Utilities.getField(fieldOwner, fieldType, null); } /** * Sets the value of a non-accessible field on a given object. *

* In the * Tutorial * * @param fieldOwner the instance on which to set the field value * @param fieldName the name of the field to set * @param fieldValue the value to set the field to * * @see #setField(Class, String, Object) */ protected final void setField(Object fieldOwner, String fieldName, Object fieldValue) { Utilities.setField(fieldOwner.getClass(), fieldOwner, fieldName, fieldValue); } /** * Same as {@link #setField(Object, String, Object)}, except that the field is looked up by the * type of the given field value instead of by name. * * @throws IllegalArgumentException if no field or more than one is found in the target class to * which the given value can be assigned */ protected final void setField(Object fieldOwner, Object fieldValue) { Utilities.setField(fieldOwner.getClass(), fieldOwner, null, fieldValue); } /** * Sets the value of a non-accessible static field on a given class. * * @param fieldOwner the class on which the static field is defined * @param fieldName the name of the field to set * @param fieldValue the value to set the field to */ protected final void setField(Class fieldOwner, String fieldName, Object fieldValue) { Utilities.setField(fieldOwner, null, fieldName, fieldValue); } /** * Same as {@link #setField(Class, String, Object)}, except that the field is looked up by the * type of the given field value instead of by name. * * @param fieldOwner the class on which the static field is defined * @param fieldValue the value to set the field to */ protected final void setField(Class fieldOwner, Object fieldValue) { Utilities.setField(fieldOwner, null, null, fieldValue); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy