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.lines;
6   
7   import static java.util.Collections.emptyList;
8   
9   import edu.umd.cs.findbugs.annotations.NonNull;
10  import edu.umd.cs.findbugs.annotations.Nullable;
11  
12  import java.util.ArrayList;
13  import java.util.Collections;
14  import java.util.List;
15  
16  import mockit.asm.controlFlow.Label;
17  import mockit.coverage.CallPoint;
18  
19  import org.checkerframework.checker.index.qual.NonNegative;
20  
21  /**
22   * Coverage data gathered for a single executable line of code in a source file.
23   */
24  public final class LineCoverageData extends LineSegmentData {
25      private static final long serialVersionUID = -6233980722802474992L;
26  
27      // Static data:
28      @NonNull
29      private List<BranchCoverageData> branches;
30      @NonNegative
31      private transient int segments;
32  
33      LineCoverageData() {
34          branches = emptyList();
35      }
36  
37      @NonNegative
38      public int addBranchingPoint(@NonNull Label jumpSource, @NonNull Label jumpTarget) {
39          int initialIndex = branches.size();
40  
41          if (initialIndex == 0) {
42              branches = new ArrayList<>(4);
43          }
44  
45          branches.add(new BranchCoverageData(jumpSource));
46          branches.add(new BranchCoverageData(jumpTarget));
47          return initialIndex;
48      }
49  
50      void markLastSegmentAsEmpty() {
51          BranchCoverageData lastBranch = branches.get(branches.size() - 1);
52          lastBranch.markAsEmpty();
53      }
54  
55      private boolean noBranchesYet() {
56          return branches == Collections.<BranchCoverageData> emptyList();
57      }
58  
59      @NonNull
60      public BranchCoverageData getBranchData(@NonNegative int index) {
61          return branches.get(index);
62      }
63  
64      boolean acceptsAdditionalCallPoints(@NonNegative int branchIndex) {
65          BranchCoverageData data = branches.get(branchIndex);
66          return data.acceptsAdditionalCallPoints();
67      }
68  
69      @NonNegative
70      int registerExecution(@NonNegative int branchIndex, @Nullable CallPoint callPoint) {
71          BranchCoverageData data = branches.get(branchIndex);
72          return data.registerExecution(callPoint);
73      }
74  
75      public boolean containsBranches() {
76          return !noBranchesYet();
77      }
78  
79      @NonNull
80      public List<BranchCoverageData> getBranches() {
81          return branches;
82      }
83  
84      boolean isValidBranch(@NonNegative int branchIndex) {
85          return branches.get(branchIndex) != BranchCoverageData.INVALID;
86      }
87  
88      @NonNegative
89      public int getNumberOfSegments() {
90          int previouslyCounted = segments;
91  
92          if (previouslyCounted > 0) {
93              return previouslyCounted;
94          }
95  
96          int n = branches.size();
97          int count = 1;
98  
99          for (int targetBranchIndex = 1; targetBranchIndex < n; targetBranchIndex += 2) {
100             BranchCoverageData targetBranch = branches.get(targetBranchIndex);
101             int targetLine = targetBranch.getLine();
102 
103             if (targetLine > 0) {
104                 BranchCoverageData sourceBranch = branches.get(targetBranchIndex - 1);
105                 int sourceLine = sourceBranch.getLine();
106 
107                 if (targetLine == sourceLine) {
108                     count++;
109                 }
110 
111                 if (!targetBranch.isEmpty()) {
112                     count++;
113                 }
114             }
115         }
116 
117         segments = count;
118         return count;
119     }
120 
121     @NonNegative
122     public int getNumberOfCoveredSegments() {
123         int segmentsCovered = isCovered() ? 1 : 0;
124         int n = branches.size();
125 
126         if (n == 0) {
127             return segmentsCovered;
128         }
129 
130         for (int sourceBranchIndex = 0; sourceBranchIndex < n; sourceBranchIndex += 2) {
131             BranchCoverageData sourceBranch = branches.get(sourceBranchIndex);
132             BranchCoverageData targetBranch = branches.get(sourceBranchIndex + 1);
133 
134             if (sourceBranch.isCovered() && !targetBranch.isEmpty()) {
135                 segmentsCovered++;
136             }
137 
138             if (targetBranch.isCovered()) {
139                 int targetLine = targetBranch.getLine();
140 
141                 if (targetLine == sourceBranch.getLine()) {
142                     segmentsCovered++;
143                 }
144             }
145         }
146 
147         return segmentsCovered;
148     }
149 
150     @NonNegative
151     public int getNumberOfBranchingSourcesAndTargets() {
152         int n = branches.size();
153 
154         if (n == 0) {
155             return 0;
156         }
157 
158         int count = 0;
159 
160         for (int sourceBranchIndex = 0; sourceBranchIndex < n; sourceBranchIndex += 2) {
161             BranchCoverageData sourceBranch = branches.get(sourceBranchIndex);
162 
163             if (!sourceBranch.isEmpty()) {
164                 count++;
165             }
166 
167             count++;
168         }
169 
170         return count;
171     }
172 
173     @NonNegative
174     public int getNumberOfCoveredBranchingSourcesAndTargets() {
175         int n = branches.size();
176 
177         if (n == 0) {
178             return 0;
179         }
180 
181         int sourcesAndTargetsCovered = 0;
182 
183         for (int sourceBranchIndex = 0; sourceBranchIndex < n; sourceBranchIndex += 2) {
184             BranchCoverageData sourceBranch = branches.get(sourceBranchIndex);
185             BranchCoverageData targetBranch = branches.get(sourceBranchIndex + 1);
186 
187             if (sourceBranch.isCovered()) {
188                 sourcesAndTargetsCovered++;
189             }
190 
191             if (targetBranch.isCovered()) {
192                 int targetLine = targetBranch.getLine();
193 
194                 if (targetLine == sourceBranch.getLine()) {
195                     sourcesAndTargetsCovered++;
196                 }
197             }
198         }
199 
200         return sourcesAndTargetsCovered;
201     }
202 
203     void addCountsFromPreviousTestRun(@NonNull LineCoverageData previousData) {
204         addExecutionCountAndCallPointsFromPreviousTestRun(previousData);
205 
206         if (containsBranches()) {
207             for (int i = 0, n = branches.size(); i < n; i++) {
208                 BranchCoverageData segmentData = branches.get(i);
209                 BranchCoverageData previousSegmentData = previousData.branches.get(i);
210 
211                 segmentData.addExecutionCountAndCallPointsFromPreviousTestRun(previousSegmentData);
212             }
213         }
214     }
215 }