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