1
2
3
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 }