/*
* 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.lang.reflect.*;
import java.util.*;
import mockit.internal.state.*;
import mockit.internal.expectations.*;
import mockit.internal.util.*;
/**
* Base class whose subclasses are defined in test code, and whose instances define a set of invocations on mocked
* types/instances to be verified against the actual invocations executed during the replay phase of the test.
* The order of the invocations is not relevant, and any subset of the potential invocations in the replay phase can be
* verified (ie, not all of them need to be verified on each use of this class).
* <p/>
* Since each user-defined subclass will typically take the form of an anonymous class with no methods but only an
* instance initialization block, we name such constructs <em>verification blocks</em>.
* When extending this class directly (as opposed to extending one of the three specializations available in the API),
* we have an <em>unordered</em> verification block.
* <p/>
* Such blocks can appear alone in a test or (more typically) in conjunction with
* {@linkplain NonStrictExpectations non-strict expectation blocks}.
* It's also possible to have an {@linkplain Expectations strict expectation block} in the same test, provided at least
* one non-strict expectation is recorded in it (strict expectations are <em>implicitly</em> verified as invocations
* occur in the replay phase, and at the end of the test to account for any missing invocations - they cannot be
* verified explicitly).
* <p/>
* Note that while an expectation block can appear only <em>before</em> the replay phase of the test, a verification
* block can appear only <em>after</em> that phase.
* <p/>
* For an invocation inside a verification block to succeed (ie, pass verification), a corresponding invocation must
* have occurred during the replay phase of the test, <em>at least once</em>.
* Such an invocation may or may not have been previously recorded in an expectation block.
* This is only the <em>default</em> verification behavior, though. Just like with recorded expectations, it's possible
* to specify different invocation count constraints through the {@link #times}, {@link #minTimes}, and
* {@link #maxTimes} fields.
* <p/>
* The mocked types used inside the verification block can be all the ones that are in scope: mock fields of the test
* class and mock parameters of the test method. In addition, local mock fields declared inside expectation blocks can
* be <em>imported</em> into the verification block by declaring a field of the desired mocked type inside this block -
* though not necessarily with the same name as the imported mock field, although it's recommended for clarity.
* <p/>
* Just like it is valid to have multiple expectation blocks in a test, it is also valid to have multiple (non-nested)
* verification blocks. The relative order of the blocks is not relevant.
* Such blocks can be of different types. (Typically, when using multiple verification blocks there will be a mix of
* ordered and unordered ones.)
* <p/>
* <a href="http://jmockit.googlecode.com/svn/trunk/www/tutorial/BehaviorBasedTesting.html#verification">In the Tutorial</a>
*
* @see Expectations#notStrict()
* @see NonStrict
* @see #Verifications()
* @see #Verifications(int)
*/
public abstract class Verifications extends Invocations
{
final BaseVerificationPhase verificationPhase;
/**
* Begins verification on the mocked types/instances invoked during the replay phase of the test.
*/
protected Verifications()
{
this(false);
}
/**
* Begins verification on the mocked types/instances invoked during the replay phase of the test, considering that
* such invocations occurred in a given number of iterations.
* <p/>
* The effect of specifying a (positive) number of iterations is equivalent to setting to that number the lower and
* upper invocation count limits for each expectation verified inside the block.
* If, however, the lower/upper limit is explicitly specified for an expectation, the given number of iterations
* becomes a multiplier.
* When not specified, at least one matching invocation will be required to have occurred; therefore, specifying
* <em>1 (one)</em> iteration is different from not specifying the number of iterations at all.
* <p/>
* <a href="http://jmockit.googlecode.com/svn/trunk/www/tutorial/BehaviorBasedTesting.html#iterations">In the Tutorial</a>
*
* @param numberOfIterations the positive number of iterations for the whole set of invocations verified inside the
* block
*
* @see #times
* @see #minTimes
* @see #maxTimes
*/
protected Verifications(int numberOfIterations)
{
this(false);
verificationPhase.setNumberOfIterations(numberOfIterations);
}
Verifications(boolean inOrder)
{
RecordAndReplayExecution instance = TestRun.getExecutingTest().getRecordAndReplayForVerifications();
Map<Type,Object> availableLocalMocks = instance.getLocalMocks();
if (!availableLocalMocks.isEmpty()) {
importMocksIntoLocalFields(getClass(), availableLocalMocks);
}
verificationPhase = instance.startVerifications(inOrder);
}
private void importMocksIntoLocalFields(Class<?> ownerClass, Map<Type, Object> localMocks)
{
Field[] fields = ownerClass.getDeclaredFields();
for (Field fieldToImport : fields) {
if (!Modifier.isFinal(fieldToImport.getModifiers())) {
importMockIntoLocalField(localMocks, fieldToImport);
}
}
Class<?> superClass = ownerClass.getSuperclass();
if (
superClass != Verifications.class && superClass != VerificationsInOrder.class &&
superClass != FullVerifications.class && superClass != FullVerificationsInOrder.class
) {
importMocksIntoLocalFields(superClass, localMocks);
}
}
private void importMockIntoLocalField(Map<Type, Object> localMocks, Field field)
{
Type mockedType = field.getGenericType();
Object owner = localMocks.get(mockedType);
if (owner != null) {
Object mock = Utilities.getField(owner.getClass(), mockedType, owner);
Utilities.setFieldValue(field, this, mock);
}
}
@Override
final BaseVerificationPhase getCurrentPhase()
{
return verificationPhase;
}
}