View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.internal.expectations.state;
6   
7   import static mockit.internal.util.Utilities.getClassType;
8   
9   import edu.umd.cs.findbugs.annotations.NonNull;
10  import edu.umd.cs.findbugs.annotations.Nullable;
11  
12  import java.lang.reflect.Type;
13  import java.util.Iterator;
14  import java.util.Map;
15  import java.util.concurrent.ConcurrentHashMap;
16  
17  import mockit.asm.types.JavaType;
18  
19  public final class CascadingTypes {
20      @NonNull
21      private final Map<Type, MockedTypeCascade> mockedTypesToCascades;
22  
23      CascadingTypes() {
24          mockedTypesToCascades = new ConcurrentHashMap<>(4);
25      }
26  
27      public void add(boolean fromMockField, @NonNull Type mockedType) {
28          Class<?> mockedClass = getClassType(mockedType);
29          String mockedTypeDesc = JavaType.getInternalName(mockedClass);
30          add(mockedTypeDesc, fromMockField, mockedType);
31      }
32  
33      @NonNull
34      MockedTypeCascade add(@NonNull String mockedTypeDesc, boolean fromMockField, @NonNull Type mockedType) {
35          MockedTypeCascade cascade = mockedTypesToCascades.get(mockedType);
36  
37          if (cascade == null) {
38              cascade = new MockedTypeCascade(fromMockField, mockedType, mockedTypeDesc);
39              mockedTypesToCascades.put(mockedType, cascade);
40          }
41  
42          return cascade;
43      }
44  
45      @NonNull
46      MockedTypeCascade getCascade(@NonNull Type mockedType) {
47          return mockedTypesToCascades.get(mockedType);
48      }
49  
50      @Nullable
51      MockedTypeCascade getCascade(@NonNull String mockedTypeDesc, @Nullable Object mockInstance) {
52          if (mockedTypesToCascades.isEmpty()) {
53              return null;
54          }
55  
56          if (mockInstance != null) {
57              MockedTypeCascade cascade = findCascadeForInstance(mockInstance);
58  
59              if (cascade != null) {
60                  return cascade;
61              }
62          }
63  
64          for (MockedTypeCascade cascade : mockedTypesToCascades.values()) {
65              if (cascade.mockedTypeDesc.equals(mockedTypeDesc)) {
66                  return cascade;
67              }
68          }
69  
70          return null;
71      }
72  
73      @Nullable
74      private MockedTypeCascade findCascadeForInstance(@NonNull Object mockInstance) {
75          for (MockedTypeCascade cascade : mockedTypesToCascades.values()) {
76              if (cascade.hasInstance(mockInstance)) {
77                  return cascade;
78              }
79          }
80  
81          return null;
82      }
83  
84      void clearNonSharedCascadingTypes() {
85          if (!mockedTypesToCascades.isEmpty()) {
86              Iterator<MockedTypeCascade> itr = mockedTypesToCascades.values().iterator();
87  
88              while (itr.hasNext()) {
89                  MockedTypeCascade cascade = itr.next();
90  
91                  if (cascade.fromMockField) {
92                      cascade.discardCascadedMocks();
93                  } else {
94                      itr.remove();
95                  }
96              }
97          }
98      }
99  
100     public void clear() {
101         mockedTypesToCascades.clear();
102     }
103 
104     void addInstance(@NonNull Type mockedType, @NonNull Object cascadingInstance) {
105         MockedTypeCascade cascade = mockedTypesToCascades.get(mockedType);
106 
107         if (cascade != null) {
108             cascade.addInstance(cascadingInstance);
109         }
110     }
111 }