/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.mockups;
import java.util.*;
import java.util.Map.*;
import java.util.regex.*;
import javax.annotation.*;
import mockit.internal.util.*;
/**
* Holds state associated with mock class containing {@linkplain mockit.Mock annotated mocks}.
*/
public final class MockStates
{
private static final Pattern SPACE = Pattern.compile(" ");
/**
* For each mockup instance and each {@code @Mock} method containing the {@code Invocation} parameter or an
* invocation count constraint, a runtime state will be kept here.
*/
@Nonnull private final Map<Object, List<MockState>> mockUpsToMockStates;
@Nonnull private final Map<Object, List<MockState>> startupMockUpsToMockStates;
public MockStates()
{
startupMockUpsToMockStates = new IdentityHashMap<Object, List<MockState>>(2);
mockUpsToMockStates = new IdentityHashMap<Object, List<MockState>>(8);
}
void addStartupMockUpAndItsMockStates(@Nonnull Object mockUp, @Nonnull List<MockState> mockStates)
{
startupMockUpsToMockStates.put(mockUp, mockStates);
}
void addMockUpAndItsMockStates(@Nonnull Object mockUp, @Nonnull List<MockState> mockStates)
{
mockUpsToMockStates.put(mockUp, mockStates);
}
public void copyMockStates(@Nonnull Object previousMockUp, @Nonnull Object newMockUp)
{
List<MockState> mockStates = mockUpsToMockStates.get(previousMockUp);
if (mockStates != null) {
List<MockState> copiedMockStates = new ArrayList<MockState>(mockStates.size());
for (MockState mockState : mockStates) {
copiedMockStates.add(new MockState(mockState));
}
mockUpsToMockStates.put(newMockUp, copiedMockStates);
}
}
public void removeClassState(@Nonnull Class<?> redefinedClass, @Nullable String internalNameForOneOrMoreMockClasses)
{
removeMockStates(redefinedClass);
if (internalNameForOneOrMoreMockClasses != null) {
if (internalNameForOneOrMoreMockClasses.indexOf(' ') < 0) {
removeMockStates(internalNameForOneOrMoreMockClasses);
}
else {
String[] mockClassesInternalNames = SPACE.split(internalNameForOneOrMoreMockClasses);
for (String mockClassInternalName : mockClassesInternalNames) {
removeMockStates(mockClassInternalName);
}
}
}
}
private void removeMockStates(@Nonnull Class<?> redefinedClass)
{
Iterator<List<MockState>> itr = mockUpsToMockStates.values().iterator();
while (itr.hasNext()) {
List<MockState> mockStates = itr.next();
MockState mockState = mockStates.get(0);
if (mockState.getRealClass() == redefinedClass) {
mockStates.clear();
itr.remove();
}
}
}
private void removeMockStates(@Nonnull String mockClassInternalName)
{
Class<?> mockUpClass = ClassLoad.loadClass(mockClassInternalName.replace('/', '.'));
Iterator<Entry<Object, List<MockState>>> itr = mockUpsToMockStates.entrySet().iterator();
while (itr.hasNext()) {
Entry<Object, List<MockState>> mockUpAndMockStates = itr.next();
Object mockUp = mockUpAndMockStates.getKey();
if (mockUp.getClass() == mockUpClass) {
itr.remove();
}
}
}
public boolean updateMockState(@Nonnull Object mockUp, int mockStateIndex)
{
MockState mockState = getMockState(mockUp, mockStateIndex);
return mockState.update();
}
@Nonnull
MockState getMockState(@Nonnull Object mockUp, int mockStateIndex)
{
List<MockState> mockStates = startupMockUpsToMockStates.get(mockUp);
if (mockStates == null) {
mockStates = mockUpsToMockStates.get(mockUp);
}
MockState mockState = mockStates.get(mockStateIndex);
assert mockState != null;
return mockState;
}
}