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