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.coverage.dataItems;
6   
7   import edu.umd.cs.findbugs.annotations.NonNull;
8   import edu.umd.cs.findbugs.annotations.Nullable;
9   
10  import java.io.IOException;
11  import java.io.ObjectInputStream;
12  import java.util.ArrayList;
13  import java.util.LinkedHashMap;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Map.Entry;
17  
18  import mockit.coverage.CoveragePercentage;
19  import mockit.coverage.data.PerFileCoverage;
20  
21  import org.checkerframework.checker.index.qual.NonNegative;
22  
23  public final class PerFileDataCoverage implements PerFileCoverage {
24      private static final long serialVersionUID = -4561686103982673490L;
25  
26      @NonNull
27      public final List<String> allFields = new ArrayList<>(2);
28      @NonNull
29      public final Map<String, StaticFieldData> staticFieldsData = new LinkedHashMap<>();
30      @NonNull
31      public final Map<String, InstanceFieldData> instanceFieldsData = new LinkedHashMap<>();
32  
33      private transient int coveredDataItems = -1;
34  
35      private void readObject(@NonNull ObjectInputStream in) throws IOException, ClassNotFoundException {
36          coveredDataItems = -1;
37          in.defaultReadObject();
38      }
39  
40      public void addField(@NonNull String className, @NonNull String fieldName, boolean isStatic) {
41          String classAndField = className + '.' + fieldName;
42  
43          if (!allFields.contains(classAndField)) {
44              allFields.add(classAndField);
45          }
46  
47          if (isStatic) {
48              staticFieldsData.put(classAndField, new StaticFieldData());
49          } else {
50              instanceFieldsData.put(classAndField, new InstanceFieldData());
51          }
52      }
53  
54      public boolean isFieldWithCoverageData(@NonNull String classAndFieldNames) {
55          return instanceFieldsData.containsKey(classAndFieldNames) || staticFieldsData.containsKey(classAndFieldNames);
56      }
57  
58      public void registerAssignmentToStaticField(@NonNull String classAndFieldNames) {
59          StaticFieldData staticData = getStaticFieldData(classAndFieldNames);
60  
61          if (staticData != null) {
62              staticData.registerAssignment();
63          }
64      }
65  
66      @Nullable
67      public StaticFieldData getStaticFieldData(@NonNull String classAndFieldNames) {
68          return staticFieldsData.get(classAndFieldNames);
69      }
70  
71      public void registerReadOfStaticField(@NonNull String classAndFieldNames) {
72          StaticFieldData staticData = getStaticFieldData(classAndFieldNames);
73  
74          if (staticData != null) {
75              staticData.registerRead();
76          }
77      }
78  
79      public void registerAssignmentToInstanceField(@NonNull Object instance, @NonNull String classAndFieldNames) {
80          InstanceFieldData instanceData = getInstanceFieldData(classAndFieldNames);
81  
82          if (instanceData != null) {
83              instanceData.registerAssignment(instance);
84          }
85      }
86  
87      @Nullable
88      public InstanceFieldData getInstanceFieldData(@NonNull String classAndFieldNames) {
89          return instanceFieldsData.get(classAndFieldNames);
90      }
91  
92      public void registerReadOfInstanceField(@NonNull Object instance, @NonNull String classAndFieldNames) {
93          InstanceFieldData instanceData = getInstanceFieldData(classAndFieldNames);
94  
95          if (instanceData != null) {
96              instanceData.registerRead(instance);
97          }
98      }
99  
100     public boolean hasFields() {
101         return !allFields.isEmpty();
102     }
103 
104     public boolean isCovered(@NonNull String classAndFieldNames) {
105         InstanceFieldData instanceData = getInstanceFieldData(classAndFieldNames);
106 
107         if (instanceData != null && instanceData.isCovered()) {
108             return true;
109         }
110 
111         StaticFieldData staticData = getStaticFieldData(classAndFieldNames);
112 
113         return staticData != null && staticData.isCovered();
114     }
115 
116     @Override
117     @NonNegative
118     public int getTotalItems() {
119         return staticFieldsData.size() + instanceFieldsData.size();
120     }
121 
122     @Override
123     @NonNegative
124     public int getCoveredItems() {
125         if (coveredDataItems >= 0) {
126             return coveredDataItems;
127         }
128 
129         coveredDataItems = 0;
130 
131         for (StaticFieldData staticData : staticFieldsData.values()) {
132             if (staticData.isCovered()) {
133                 coveredDataItems++;
134             }
135         }
136 
137         for (InstanceFieldData instanceData : instanceFieldsData.values()) {
138             if (instanceData.isCovered()) {
139                 coveredDataItems++;
140             }
141         }
142 
143         return coveredDataItems;
144     }
145 
146     @Override
147     public int getCoveragePercentage() {
148         int totalFields = getTotalItems();
149 
150         if (totalFields == 0) {
151             return -1;
152         }
153 
154         int coveredFields = getCoveredItems();
155         return CoveragePercentage.calculate(coveredFields, totalFields);
156     }
157 
158     public void mergeInformation(@NonNull PerFileDataCoverage previousInfo) {
159         addInfoFromPreviousTestRun(staticFieldsData, previousInfo.staticFieldsData);
160         addFieldsFromPreviousTestRunIfAbsent(staticFieldsData, previousInfo.staticFieldsData);
161 
162         addInfoFromPreviousTestRun(instanceFieldsData, previousInfo.instanceFieldsData);
163         addFieldsFromPreviousTestRunIfAbsent(instanceFieldsData, previousInfo.instanceFieldsData);
164     }
165 
166     private static <FI extends FieldData> void addInfoFromPreviousTestRun(@NonNull Map<String, FI> currentInfo,
167             @NonNull Map<String, FI> previousInfo) {
168         for (Entry<String, FI> nameAndInfo : currentInfo.entrySet()) {
169             String fieldName = nameAndInfo.getKey();
170             FieldData previousFieldInfo = previousInfo.get(fieldName);
171 
172             if (previousFieldInfo != null) {
173                 FieldData fieldInfo = nameAndInfo.getValue();
174                 fieldInfo.addCountsFromPreviousTestRun(previousFieldInfo);
175             }
176         }
177     }
178 
179     private static <FI extends FieldData> void addFieldsFromPreviousTestRunIfAbsent(
180             @NonNull Map<String, FI> currentInfo, @NonNull Map<String, FI> previousInfo) {
181         for (Entry<String, FI> nameAndInfo : previousInfo.entrySet()) {
182             String fieldName = nameAndInfo.getKey();
183 
184             if (!currentInfo.containsKey(fieldName)) {
185                 currentInfo.put(fieldName, previousInfo.get(fieldName));
186             }
187         }
188     }
189 }