1
2
3
4
5
6 package mockit.internal.faking;
7
8 import edu.umd.cs.findbugs.annotations.NonNull;
9 import edu.umd.cs.findbugs.annotations.Nullable;
10
11 import java.util.ArrayList;
12 import java.util.IdentityHashMap;
13 import java.util.Iterator;
14 import java.util.LinkedHashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
19 import java.util.regex.Pattern;
20
21 import mockit.internal.util.ClassLoad;
22
23 import org.checkerframework.checker.index.qual.NonNegative;
24
25
26
27
28 public final class FakeStates {
29 private static final Pattern SPACE = Pattern.compile(" ");
30
31
32
33
34
35 @NonNull
36 private final Map<Object, List<FakeState>> fakesToFakeStates;
37 @NonNull
38 private final Map<Object, List<FakeState>> startupFakesToFakeStates;
39 @NonNull
40 private final Set<FakeState> fakeStatesWithExpectations;
41
42 public FakeStates() {
43 startupFakesToFakeStates = new IdentityHashMap<>(2);
44 fakesToFakeStates = new IdentityHashMap<>(8);
45 fakeStatesWithExpectations = new LinkedHashSet<>(8);
46 }
47
48 void addStartupFakeAndItsFakeStates(@NonNull Object fake, @NonNull List<FakeState> fakeStates) {
49 startupFakesToFakeStates.put(fake, fakeStates);
50 registerExpectations(fakeStates);
51 }
52
53 void addFakeAndItsFakeStates(@NonNull Object fake, @NonNull List<FakeState> fakeStates) {
54 fakesToFakeStates.put(fake, fakeStates);
55 registerExpectations(fakeStates);
56 }
57
58 public void copyFakeStates(@NonNull Object previousFake, @NonNull Object newFake) {
59 List<FakeState> fakeStates = fakesToFakeStates.get(previousFake);
60
61 if (fakeStates != null) {
62 List<FakeState> copiedFakeStates = new ArrayList<>(fakeStates.size());
63
64 for (FakeState fakeState : fakeStates) {
65 copiedFakeStates.add(new FakeState(fakeState));
66 }
67
68 fakesToFakeStates.put(newFake, copiedFakeStates);
69 registerExpectations(copiedFakeStates);
70 }
71 }
72
73 public void removeClassState(@NonNull Class<?> redefinedClass,
74 @Nullable String internalNameForOneOrMoreFakeClasses) {
75 removeFakeStates(redefinedClass);
76
77 if (internalNameForOneOrMoreFakeClasses != null) {
78 if (internalNameForOneOrMoreFakeClasses.indexOf(' ') < 0) {
79 removeFakeStates(internalNameForOneOrMoreFakeClasses);
80 } else {
81 String[] fakeClassesInternalNames = SPACE.split(internalNameForOneOrMoreFakeClasses);
82
83 for (String fakeClassInternalName : fakeClassesInternalNames) {
84 removeFakeStates(fakeClassInternalName);
85 }
86 }
87 }
88 }
89
90 private void removeFakeStates(@NonNull Class<?> redefinedClass) {
91 Iterator<List<FakeState>> itr = fakesToFakeStates.values().iterator();
92
93 while (itr.hasNext()) {
94 List<FakeState> fakeStates = itr.next();
95 FakeState fakeState = fakeStates.get(0);
96
97 if (fakeState.getRealClass() == redefinedClass) {
98 fakeStates.forEach(fakeStatesWithExpectations::remove);
99 fakeStates.clear();
100 itr.remove();
101 }
102 }
103 }
104
105 private void removeFakeStates(@NonNull String fakeClassInternalName) {
106 Class<?> fakeClass = ClassLoad.loadClass(fakeClassInternalName.replace('/', '.'));
107 Iterator<Entry<Object, List<FakeState>>> itr = fakesToFakeStates.entrySet().iterator();
108
109 while (itr.hasNext()) {
110 Entry<Object, List<FakeState>> fakeAndFakeStates = itr.next();
111 Object fake = fakeAndFakeStates.getKey();
112
113 if (fake.getClass() == fakeClass) {
114 fakeAndFakeStates.getValue().forEach(fakeStatesWithExpectations::remove);
115 itr.remove();
116 }
117 }
118 }
119
120 public boolean updateFakeState(@NonNull Object fake, @NonNegative int fakeStateIndex) {
121 FakeState fakeState = getFakeState(fake, fakeStateIndex);
122 return fakeState.update();
123 }
124
125 @NonNull
126 FakeState getFakeState(@NonNull Object fake, @NonNegative int fakeStateIndex) {
127 List<FakeState> fakeStates = startupFakesToFakeStates.get(fake);
128
129 if (fakeStates == null) {
130 fakeStates = fakesToFakeStates.get(fake);
131 }
132
133 FakeState fakeState = fakeStates.get(fakeStateIndex);
134 assert fakeState != null;
135 return fakeState;
136 }
137
138 public void verifyMissingInvocations() {
139 for (FakeState fakeState : fakeStatesWithExpectations) {
140 fakeState.verifyMissingInvocations();
141 }
142 }
143
144 public void resetExpectations() {
145 for (FakeState fakeState : fakeStatesWithExpectations) {
146 fakeState.reset();
147 }
148 }
149
150 private void registerExpectations(@NonNull List<FakeState> fakeStates) {
151 for (FakeState fakeState : fakeStates) {
152 if (fakeState.isWithExpectations()) {
153 fakeStatesWithExpectations.add(fakeState);
154 }
155 }
156 }
157 }