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-2013 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.*;
import java.util.regex.*;

import org.jetbrains.annotations.*;

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(); }

   /**
    * Matches any {@code Object} reference passed as value for the parameter.
    * 

* The use of this field will usually require a cast to the specific parameter type. * However, if there is any other parameter for which an argument matching constraint is specified, passing the * {@code null} reference instead will have the same effect. *

* When the parameter to be matched is a varargs parameter of element type {@code V}, the use of * {@code any} should be cast to {@code V[]}. *

* In invocations to non-accessible methods or constructors (for example, with * {@link Deencapsulation#invoke(Object, String, Object...)}), use {@link #withAny} instead. * * @see #anyInt */ protected 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 final String anyString = new String(); /** * Matches any {@code long} or {@code Long} value for the relevant parameter. * * @see #anyInt */ protected 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 final Integer anyInt = 0; /** * Matches any {@code short} or {@code Short} value for the relevant parameter. * * @see #anyInt */ protected final Short anyShort = 0; /** * Matches any {@code byte} or {@code Byte} value for the relevant parameter. * * @see #anyInt */ protected final Byte anyByte = 0; /** * Matches any {@code boolean} or {@code Boolean} value for the relevant parameter. * * @see #anyInt */ protected final Boolean anyBoolean = false; /** * Matches any {@code char} or {@code Character} value for the relevant parameter. * * @see #anyInt */ protected final Character anyChar = '\0'; /** * Matches any {@code double} or {@code Double} value for the relevant parameter. * * @see #anyInt */ protected final Double anyDouble = 0.0; /** * Matches any {@code float} or {@code Float} value for the relevant parameter. * * @see #anyInt */ protected 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, and should either have no parameters or a list of parameters * that match the ones defined in the mocked method/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 JUnit/TestNG assertion methods. *

* The validation method can optionally declare its first parameter as being of type {@link mockit.Invocation}. * * @deprecated To validate arguments received by invocations that match a recorded or verified expectation, use * {@link #withCapture(java.util.List)} or {@link Verifications#withCapture() withCapture()} instead. * If an {@link Invocation} object is needed, use a {@link Delegate} object recorded as the expectation * {@link Expectations#result result}. */ @Deprecated protected 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 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 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 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 CharSequence $; @NotNull 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 */ @NotNull 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. * 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 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, @NotNull 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(Object, 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) */ @Nullable protected final T with(@NotNull 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. * 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 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) */ @Nullable protected final T with(@NotNull Delegate delegateObjectWithInvocationHandlerMethod) { addMatcher(new ReflectiveMatcher(delegateObjectWithInvocationHandlerMethod)); Class delegateClass = delegateObjectWithInvocationHandlerMethod.getClass(); Type[] genericInterfaces = delegateClass.getGenericInterfaces(); while (genericInterfaces.length == 0) { delegateClass = delegateClass.getSuperclass(); genericInterfaces = delegateClass.getGenericInterfaces(); } ParameterizedType type = (ParameterizedType) genericInterfaces[0]; Type parameterType = type.getActualTypeArguments()[0]; return DefaultValues.computeForWrapperType(parameterType); } private void addMatcher(@NotNull 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 Deencapsulation#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; } /** * Captures the argument value passed into the associated expectation parameter, for each invocation that matches the * expectation when the tested code is exercised. * As each such value is captured, it gets added to the given list so that it can be inspected later. * * @param valueHolderForMultipleInvocations list into which the arguments received by matching invocations will be * added * * @return the default value for type {@code T} * * @see Verifications#withCapture() */ @Nullable protected final T withCapture(@NotNull final List valueHolderForMultipleInvocations) { addMatcher(new ArgumentMatcher() { public boolean matches(@Nullable Object replayValue) { //noinspection unchecked valueHolderForMultipleInvocations.add((T) replayValue); return true; } public void writeMismatchPhrase(@NotNull ArgumentMismatch argumentMismatch) {} }); return null; } /** * When passed as argument for an expectation, creates a new matcher that will check if the given value is * {@link Object#equals(Object) equal} to the corresponding argument received by a matching invocation. *

* 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 */ @NotNull protected final T withInstanceLike(@NotNull 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)} */ @Nullable protected final T withInstanceOf(@NotNull 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} */ @Nullable 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} */ @Nullable 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 */ @NotNull protected final T withSubstring(@NotNull 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 */ @NotNull protected final T withPrefix(@NotNull 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 */ @NotNull protected final T withSuffix(@NotNull 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) */ @NotNull protected final T withMatch(@NotNull T regex) { addMatcher(new PatternMatcher(regex.toString())); return regex; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy