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

mockit.Invocations Maven / Gradle / Ivy

/*
 * JMockit Expectations & Verifications
 * Copyright (c) 2006-2010 Rogério Liesenfeld
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
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. *

* 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(); final Expectation getCurrentExpectation() { return getCurrentPhase().getCurrentExpectation(); } /** * 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. *

* In the Tutorial * * @param arg the expected argument value * * @return the input 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. */ 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. */ 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 call withInstanceOf(arg.getClass()), except that it returns * {@code arg} instead of {@code null}. */ 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. * * @return always 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. */ 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. */ 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. */ 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. */ 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. */ 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). * * @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 expected constructor invocation for a given class. *

* This is useful for invoking non-accessible constructors (private ones, for example) from the * test, which otherwise could not be called normally. *

* In the Tutorial * * @param className the fully qualified name of the desired class (which should not be accessible * to the test; otherwise just refer to it in code) * @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 for the case where each * initialization argument is known to be null or non-null at the call point. *

* However, {@code null} argument values cannot directly be passed to this method; * if the parameter value must be {@code null}, then the corresponding {@code Class} literal 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 */ 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 expected invocation to a given instance method, with a given list of arguments. *

* This is useful when the next expected method is not accessible (private, for example) from the test, and * therefore can not be called normally. It should not be used for calling 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, not a mocked instance. *

* In the Tutorial * * @param fieldOwner 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 invocation; if a * null value needs to be passed, the Class object for the parameter type must be passed instead * * @return the return value from the invoked method, wrapped if primitive * * @see #invoke(Class, String, Object...) */ protected final T invoke(Object fieldOwner, String methodName, Object... methodArgs) { //noinspection unchecked return (T) Utilities.invoke(fieldOwner.getClass(), fieldOwner, methodName, methodArgs); } /** * Specifies an expected invocation to a given static method, with a given list of arguments. *

* This is useful when the next expected method is not accessible (private, for example) from the * test, and therefore cannot be called normally. It should not be used for * calling 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 will normally be a "real", non-mocked, class in the code under test. * * @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 invocation; if a * null value needs to be passed, the Class object for the parameter type must be passed instead */ 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 - 2025 Weber Informatics LLC | Privacy Policy