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-2012 Rogério Liesenfeld
 * This file is subject to the terms of the MIT license (see LICENSE.txt).
 */
package mockit;

import java.lang.reflect.*;
import java.util.regex.*;

import mockit.internal.expectations.argumentMatching.ArgumentMatcher;
import mockit.internal.expectations.*;
import mockit.internal.expectations.argumentMatching.*;
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(false); }

   /**
    * 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 called back for each invocation matching the current expectation, * in order to validate invocation arguments. *

* Said object can be of any type, provided its class has a single non-private method * (additional methods are allowed and ignored, as long as they are {@code private}). * This validation method can have any name, provided 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 validation method. *

* The return type of the validation method should be either {@code boolean} or {@code void}. * In the first case, a return value of {@code true} means the invocation is valid, while {@code false} causes the * test to fail with an appropriate error message. * In the second case, invocation arguments should be validated through regular assertions (Java * asserts and/or JUnit/TestNG methods). *

* The validation method can optionally 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 $; 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 expectation. *

* The given matcher can be any existing Hamcrest matcher or a user provided one. *

* Alternatively, it can be an instance of an invocation handler class, similar to those used with the * {@linkplain #forEachInvocation} field. * In this case, the non-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 case of a {@code void} return type, instead of returning a value the 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 * an instance of an invocation handler class containing an appropriate invocation handler method * * @return the given {@code argValue} * * @see #with(Object) * @see #with(Delegate) */ 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 expectation. * This works just like {@link #with(T, Object)}, but attempting to discover the argument type from the supplied * Hamcrest argument matcher, when applicable. * * @param argumentMatcher an instance of a class implementing the {@code org.hamcrest.Matcher} interface, or * an instance of an invocation handler class containing an appropriate invocation handler method * * @return the value recorded inside the given Hamcrest argument matcher, or {@code null} if there is no * such value to be found * * @see #with(Object, Object) * @see #with(Delegate) */ protected final T with(Object argumentMatcher) { ArgumentMatcher matcher = HamcrestAdapter.create(argumentMatcher); addMatcher(matcher); if (matcher instanceof HamcrestAdapter) { Object argValue = ((HamcrestAdapter) matcher).getInnerValue(); //noinspection unchecked return (T) argValue; } return null; } /** * Adds a custom argument matcher for a parameter in the current expectation. *

* The given delegate object is assumed to be an instance of an invocation handler class, similar to those * used with the {@linkplain #forEachInvocation} field. * The non-private handler method must have a single parameter capable of receiving the * relevant argument values. * The name of this handler method does not matter. *

* The handler's return type, on the other hand, should 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 fail to match the invocation. * In the case of a {@code void} return type, the handler method should validate the actual invocation argument * through an {@code assert} statement or a JUnit/TestNG assertion. * * @param delegateObjectWithInvocationHandlerMethod an instance of a class with an appropriate invocation handler * method * * @return the default primitive value corresponding to {@code T} if it's a primitive wrapper type, or {@code null} * otherwise * * @see #with(Object) * @see #with(Object, Object) */ protected final T with(Delegate delegateObjectWithInvocationHandlerMethod) { addMatcher(new ReflectiveMatcher(delegateObjectWithInvocationHandlerMethod)); Class delegateClass = delegateObjectWithInvocationHandlerMethod.getClass(); ParameterizedType type = (ParameterizedType) delegateClass.getGenericInterfaces()[0]; Type parameterType = type.getActualTypeArguments()[0]; //noinspection unchecked return (T) DefaultValues.computeForWrapperType(parameterType); } private void addMatcher(ArgumentMatcher 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(AlwaysTrueMatcher.INSTANCE); 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) { addMatcher(new EqualityMatcher(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 NumericEqualityMatcher(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 NumericEqualityMatcher(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 ClassMatcher(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 ClassMatcher(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) { addMatcher(new InequalityMatcher(arg)); return arg; } /** * 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(NullityMatcher.INSTANCE); return null; } /** * 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(NonNullityMatcher.INSTANCE); 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) { addMatcher(new SamenessMatcher(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 StringContainmentMatcher(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 StringPrefixMatcher(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 StringSuffixMatcher(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) { addMatcher(new PatternMatcher(regex.toString())); 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