View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package integration.tests;
7   
8   import static java.lang.reflect.Modifier.isAbstract;
9   import static java.lang.reflect.Modifier.isFinal;
10  
11  import static org.junit.jupiter.api.Assertions.assertEquals;
12  import static org.junit.jupiter.api.Assertions.assertFalse;
13  import static org.junit.jupiter.api.Assertions.assertNotNull;
14  import static org.junit.jupiter.api.Assertions.assertTrue;
15  
16  import edu.umd.cs.findbugs.annotations.NonNull;
17  import edu.umd.cs.findbugs.annotations.Nullable;
18  
19  import java.lang.reflect.Field;
20  import java.util.List;
21  import java.util.Map;
22  
23  import mockit.coverage.CallPoint;
24  import mockit.coverage.data.CoverageData;
25  import mockit.coverage.data.FileCoverageData;
26  import mockit.coverage.dataItems.InstanceFieldData;
27  import mockit.coverage.dataItems.PerFileDataCoverage;
28  import mockit.coverage.dataItems.StaticFieldData;
29  import mockit.coverage.lines.BranchCoverageData;
30  import mockit.coverage.lines.LineCoverageData;
31  import mockit.coverage.lines.PerFileLineCoverage;
32  
33  import org.checkerframework.checker.index.qual.NonNegative;
34  import org.junit.jupiter.api.BeforeEach;
35  
36  @SuppressWarnings("JUnitTestCaseWithNoTests")
37  public class CoverageTest {
38      @Nullable
39      protected static FileCoverageData fileData;
40      @Nullable
41      private static String testedClassSimpleName;
42  
43      @BeforeEach
44      protected final void findCoverageData() throws Exception {
45          Field testedField = getClass().getDeclaredField("tested");
46          Class<?> testedClass = testedField.getType();
47  
48          if (testedClass != Object.class) {
49              findFileDate(testedClass);
50              setTestedFieldToNewInstanceIfApplicable(testedField);
51          }
52      }
53  
54      private void findFileDate(@NonNull Class<?> testedClass) {
55          testedClassSimpleName = testedClass.getSimpleName();
56  
57          String classFilePath = testedClass.getName().replace('.', '/') + ".java";
58          Map<String, FileCoverageData> data = CoverageData.instance().getFileToFileData();
59          fileData = data.get(classFilePath);
60  
61          assertNotNull(fileData, "FileCoverageData not found for " + classFilePath);
62      }
63  
64      private void setTestedFieldToNewInstanceIfApplicable(@NonNull Field testedField) throws Exception {
65          Class<?> testedClass = testedField.getType();
66  
67          if (!testedClass.isEnum() && !isAbstract(testedClass.getModifiers()) && !isFinal(testedField.getModifiers())) {
68              testedField.setAccessible(true);
69  
70              if (testedField.get(this) == null) {
71                  // noinspection ClassNewInstance
72                  Object newTestedInstance = testedClass.getDeclaredConstructor().newInstance();
73  
74                  testedField.set(this, newTestedInstance);
75              }
76          }
77      }
78  
79      @NonNull
80      private FileCoverageData fileData() {
81          if (fileData == null) {
82              Object testedInstance;
83  
84              try {
85                  Field testedField = getClass().getDeclaredField("tested");
86                  testedInstance = testedField.get(this);
87              } catch (NoSuchFieldException | IllegalAccessException e) {
88                  throw new RuntimeException(e);
89              }
90  
91              Class<?> testedClass = testedInstance.getClass();
92              findFileDate(testedClass);
93          }
94  
95          return fileData;
96      }
97  
98      // Line Coverage assertions
99      // ////////////////////////////////////////////////////////////////////////////////////////////////////////////
100 
101     protected final void assertLines(@NonNegative int startingLine, @NonNegative int endingLine,
102             @NonNegative int expectedLinesExecuted) {
103         PerFileLineCoverage lineCoverageInfo = fileData().lineCoverageInfo;
104         int lineCount = lineCoverageInfo.getLineCount();
105         assertTrue(lineCount >= startingLine, "Starting line not found");
106         assertTrue(lineCount >= endingLine, "Ending line not found");
107 
108         int linesExecuted = 0;
109 
110         for (int line = startingLine; line <= endingLine; line++) {
111             if (lineCoverageInfo.getExecutionCount(line) > 0) {
112                 linesExecuted++;
113             }
114         }
115 
116         assertEquals(expectedLinesExecuted, linesExecuted, "Unexpected number of lines executed:");
117     }
118 
119     protected final void assertLine(@NonNegative int line, @NonNegative int expectedSegments,
120             @NonNegative int expectedCoveredSegments, int... expectedExecutionCounts) {
121         PerFileLineCoverage info = fileData().lineCoverageInfo;
122         LineCoverageData lineData = info.getLineData(line);
123 
124         assertEquals(expectedSegments, info.getNumberOfSegments(line), "Segments:");
125         assertEquals(expectedCoveredSegments, lineData.getNumberOfCoveredSegments(), "Covered segments:");
126         assertEquals(expectedExecutionCounts[0], info.getExecutionCount(line), "Execution count:");
127 
128         for (int i = 1; i < expectedExecutionCounts.length; i++) {
129             BranchCoverageData segmentData = lineData.getBranchData(i - 1);
130 
131             int executionCount = segmentData.getExecutionCount();
132             assertEquals(expectedExecutionCounts[i], executionCount,
133                     "Execution count for line " + line + ", segment " + i + ':');
134 
135             List<CallPoint> callPoints = segmentData.getCallPoints();
136 
137             if (callPoints != null) {
138                 int callPointCount = 0;
139 
140                 for (CallPoint callPoint : callPoints) {
141                     callPointCount++;
142                     callPointCount += callPoint.getRepetitionCount();
143                 }
144 
145                 assertEquals(executionCount, callPointCount, "Missing call points for line " + line + ", segment " + i);
146             }
147         }
148     }
149 
150     protected final void assertBranchingPoints(@NonNegative int line, @NonNegative int expectedSourcesAndTargets,
151             @NonNegative int expectedCoveredSourcesAndTargets) {
152         PerFileLineCoverage lineCoverageInfo = fileData().lineCoverageInfo;
153         LineCoverageData lineData = lineCoverageInfo.getLineData(line);
154 
155         int sourcesAndTargets = lineCoverageInfo.getNumberOfBranchingSourcesAndTargets(line);
156         assertEquals(expectedSourcesAndTargets, sourcesAndTargets, "Sources and targets:");
157 
158         int coveredSourcesAndTargets = lineData.getNumberOfCoveredBranchingSourcesAndTargets();
159         assertEquals(expectedCoveredSourcesAndTargets, coveredSourcesAndTargets, "Covered sources and targets:");
160     }
161 
162     // Data Coverage assertions
163     // ////////////////////////////////////////////////////////////////////////////////////////////////////////////
164 
165     protected final void assertFieldIgnored(@NonNull String fieldName) {
166         String fieldId = testedClassSimpleName + '.' + fieldName;
167         PerFileDataCoverage info = fileData().dataCoverageInfo;
168         assertFalse(info.staticFieldsData.containsKey(fieldId),
169                 "Field " + fieldName + " should not have static coverage data");
170         assertFalse(info.instanceFieldsData.containsKey(fieldId),
171                 "Field " + fieldName + " should not have instance coverage data");
172     }
173 
174     protected static void assertStaticFieldCovered(@NonNull String fieldName) {
175         assertTrue(isStaticFieldCovered(fieldName), "Static field " + fieldName + " should be covered");
176     }
177 
178     private static boolean isStaticFieldCovered(@NonNull String fieldName) {
179         String classAndFieldNames = testedClassSimpleName + '.' + fieldName;
180         StaticFieldData staticFieldData = fileData.dataCoverageInfo.staticFieldsData.get(classAndFieldNames);
181 
182         return staticFieldData.isCovered();
183     }
184 
185     protected static void assertStaticFieldUncovered(@NonNull String fieldName) {
186         assertFalse(isStaticFieldCovered(fieldName), "Static field " + fieldName + " should not be covered");
187     }
188 
189     protected static void assertInstanceFieldCovered(@NonNull String fieldName) {
190         assertTrue(isInstanceFieldCovered(fieldName), "Instance field " + fieldName + " should be covered");
191     }
192 
193     private static boolean isInstanceFieldCovered(@NonNull String fieldName) {
194         return getInstanceFieldData(fieldName).isCovered();
195     }
196 
197     private static InstanceFieldData getInstanceFieldData(@NonNull String fieldName) {
198         String classAndFieldNames = testedClassSimpleName + '.' + fieldName;
199         return fileData.dataCoverageInfo.instanceFieldsData.get(classAndFieldNames);
200     }
201 
202     protected static void assertInstanceFieldUncovered(@NonNull String fieldName) {
203         assertFalse(isInstanceFieldCovered(fieldName), "Instance field " + fieldName + " should not be covered");
204     }
205 
206     protected static void assertInstanceFieldUncovered(@NonNull String fieldName,
207             @NonNull Object... uncoveredInstances) {
208         String msg = "Instance field " + fieldName + " should not be covered";
209         InstanceFieldData fieldData = getInstanceFieldData(fieldName);
210         List<Integer> ownerInstances = fieldData.getOwnerInstancesWithUnreadAssignments();
211 
212         assertEquals(uncoveredInstances.length, ownerInstances.size(), msg);
213 
214         for (Object uncoveredInstance : uncoveredInstances) {
215             Integer instanceId = System.identityHashCode(uncoveredInstance);
216             assertTrue(ownerInstances.contains(instanceId), msg);
217         }
218     }
219 
220     protected static void verifyDataCoverage(@NonNegative int expectedItems, @NonNegative int expectedCoveredItems,
221             @NonNegative int expectedCoverage) {
222         PerFileDataCoverage info = fileData.dataCoverageInfo;
223         assertEquals(expectedItems, info.getTotalItems(), "Total data items:");
224         assertEquals(expectedCoveredItems, info.getCoveredItems(), "Covered data items:");
225         assertEquals(expectedCoverage, info.getCoveragePercentage(), "Data coverage:");
226     }
227 }