001    /*
002     * Cobertura - http://cobertura.sourceforge.net/
003     *
004     * Copyright (C) 2003 jcoverage ltd.
005     * Copyright (C) 2005 Mark Doliner
006     * Copyright (C) 2005 Mark Sinke
007     * Copyright (C) 2006 Jiri Mares
008     *
009     * Cobertura is free software; you can redistribute it and/or modify
010     * it under the terms of the GNU General Public License as published
011     * by the Free Software Foundation; either version 2 of the License,
012     * or (at your option) any later version.
013     *
014     * Cobertura is distributed in the hope that it will be useful, but
015     * WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * General Public License for more details.
018     *
019     * You should have received a copy of the GNU General Public License
020     * along with Cobertura; if not, write to the Free Software
021     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
022     * USA
023     */
024    
025    package net.sourceforge.cobertura.coveragedata;
026    
027    import java.io.Serializable;
028    import java.util.ArrayList;
029    import java.util.List;
030    
031    import net.sourceforge.cobertura.util.StringUtil;
032    
033    /**
034     * <p>
035     * This class implements HasBeenInstrumented so that when cobertura
036     * instruments itself, it will omit this class.  It does this to
037     * avoid an infinite recursion problem because instrumented classes
038     * make use of this class.
039     * </p>
040     */
041    public class LineData
042                    implements Comparable, CoverageData, HasBeenInstrumented, Serializable
043    {
044            private static final long serialVersionUID = 4;
045    
046            private long hits;
047            private List jumps;
048            private List switches;
049            private final int lineNumber;
050            private String methodDescriptor;
051            private String methodName;
052    
053            LineData(int lineNumber)
054            {
055                    this(lineNumber, null, null);
056            }
057    
058            LineData(int lineNumber, String methodName, String methodDescriptor)
059            {
060                    this.hits = 0;
061                    this.jumps = null;
062                    this.lineNumber = lineNumber;
063                    this.methodName = methodName;
064                    this.methodDescriptor = methodDescriptor;
065            }
066    
067            /**
068             * This is required because we implement Comparable.
069             */
070            public int compareTo(Object o)
071            {
072                    if (!o.getClass().equals(LineData.class))
073                            return Integer.MAX_VALUE;
074                    return this.lineNumber - ((LineData)o).lineNumber;
075            }
076    
077            public boolean equals(Object obj)
078            {
079                    if (this == obj)
080                            return true;
081                    if ((obj == null) || !(obj.getClass().equals(this.getClass())))
082                            return false;
083    
084                    LineData lineData = (LineData)obj;
085                    return (this.hits == lineData.hits)
086                                    && ((this.jumps == lineData.jumps) || ((this.jumps != null) && (this.jumps.equals(lineData.jumps))))
087                                    && ((this.switches == lineData.switches) || ((this.switches != null) && (this.switches.equals(lineData.switches))))
088                                    && (this.lineNumber == lineData.lineNumber)
089                                    && (this.methodDescriptor.equals(lineData.methodDescriptor))
090                                    && (this.methodName.equals(lineData.methodName));
091            }
092    
093            public double getBranchCoverageRate()
094            {
095                    if (getNumberOfValidBranches() == 0)
096                            return 1d;
097                    return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches();
098            }
099    
100            public String getConditionCoverage()
101            {
102                    StringBuffer ret = new StringBuffer();
103                    if (getNumberOfValidBranches() == 0)
104                    {
105                            ret.append(StringUtil.getPercentValue(1.0));
106                    }
107                    else
108                    {
109                            ret.append(StringUtil.getPercentValue(getBranchCoverageRate()));
110                            ret.append(" (").append(getNumberOfCoveredBranches()).append("/").append(getNumberOfValidBranches()).append(")");
111                    }
112                    return ret.toString();
113            }
114            
115            public long getHits()
116            {
117                    return hits;
118            }
119    
120            public boolean isCovered()
121            {
122                    return (getHits() > 0) && ((getNumberOfValidBranches() == 0) || ((1.0 - getBranchCoverageRate()) < 0.0001));
123            }
124            
125            public double getLineCoverageRate()
126            {
127                    return (getHits() > 0) ? 1 : 0;
128            }
129    
130            public int getLineNumber()
131            {
132                    return lineNumber;
133            }
134    
135            public String getMethodDescriptor()
136            {
137                    return methodDescriptor;
138            }
139    
140            public String getMethodName()
141            {
142                    return methodName;
143            }
144    
145            /**
146             * @see net.sourceforge.cobertura.coveragedata.CoverageData#getNumberOfCoveredBranches()
147             */
148            /*public int getNumberOfCoveredBranches()
149            {
150                    if (this.branches == null) 
151                            return 0;
152                    int covered = 0;
153                    for (Iterator i = this.branches.iterator(); i.hasNext(); covered += ((BranchData) i.next()).getNumberOfCoveredBranches());
154                    return covered;
155            }*/
156    
157            public int getNumberOfCoveredLines()
158            {
159                    return (getHits() > 0) ? 1 : 0;
160            }
161    
162            public int getNumberOfValidBranches()
163            {
164                    int ret = 0;
165                    if (jumps != null)
166                            for (int i = jumps.size() - 1; i >= 0; i--)
167                                    ret += ((JumpData) jumps.get(i)).getNumberOfValidBranches();
168                    if (switches != null)
169                            for (int i = switches.size() - 1; i >= 0; i--)
170                                    ret += ((SwitchData) switches.get(i)).getNumberOfValidBranches();
171                    return ret;
172            }
173            
174            public int getNumberOfCoveredBranches()
175            {
176                    int ret = 0;
177                    if (jumps != null)
178                            for (int i = jumps.size() - 1; i >= 0; i--)
179                                    ret += ((JumpData) jumps.get(i)).getNumberOfCoveredBranches();
180                    if (switches != null)
181                            for (int i = switches.size() - 1; i >= 0; i--)
182                                    ret += ((SwitchData) switches.get(i)).getNumberOfCoveredBranches();
183                    return ret;
184            }
185    
186            public int getNumberOfValidLines()
187            {
188                    return 1;
189            }
190    
191            public int hashCode()
192            {
193                    return this.lineNumber;
194            }
195    
196            public boolean hasBranch()
197            {
198                    return (jumps != null) || (switches != null);
199            }
200    
201            public void merge(CoverageData coverageData)
202            {
203                    LineData lineData = (LineData)coverageData;
204                    this.hits += lineData.hits;
205                    if (lineData.jumps != null)
206                            if (this.jumps == null) 
207                                    this.jumps = lineData.jumps;
208                            else
209                            {
210                                    for (int i = Math.min(this.jumps.size(), lineData.jumps.size()) - 1; i >= 0; i--)
211                                            ((JumpData) this.jumps.get(i)).merge((JumpData) lineData.jumps.get(i));
212                                    for (int i = Math.min(this.jumps.size(), lineData.jumps.size()); i < lineData.jumps.size(); i++) 
213                                            this.jumps.add(lineData.jumps.get(i));
214                            }
215                    if (lineData.switches != null)
216                            if (this.switches == null) 
217                                    this.switches = lineData.switches;
218                            else
219                            {
220                                    for (int i = Math.min(this.switches.size(), lineData.switches.size()) - 1; i >= 0; i--)
221                                            ((SwitchData) this.switches.get(i)).merge((SwitchData) lineData.switches.get(i));
222                                    for (int i = Math.min(this.switches.size(), lineData.switches.size()); i < lineData.switches.size(); i++) 
223                                            this.switches.add(lineData.switches.get(i));
224                            }
225                    if (lineData.methodName != null)
226                            this.methodName = lineData.methodName;
227                    if (lineData.methodDescriptor != null)
228                            this.methodDescriptor = lineData.methodDescriptor;
229            }
230    
231            void addJump(int jumpNumber)
232            {
233                    getJumpData(jumpNumber);
234            }
235    
236            void addSwitch(int switchNumber, int[] keys)
237            {
238                    getSwitchData(switchNumber, new SwitchData(switchNumber, keys));
239            }
240    
241            void addSwitch(int switchNumber, int min, int max)
242            {
243                    getSwitchData(switchNumber, new SwitchData(switchNumber, min, max));
244            }
245    
246            void setMethodNameAndDescriptor(String name, String descriptor)
247            {
248                    this.methodName = name;
249                    this.methodDescriptor = descriptor;
250            }
251    
252            void touch()
253            {
254                    this.hits++;
255            }
256            
257            void touchJump(int jumpNumber, boolean branch) 
258            {
259                    getJumpData(jumpNumber).touchBranch(branch);
260            }
261            
262            void touchSwitch(int switchNumber, int branch) 
263            {
264                    getSwitchData(switchNumber, null).touchBranch(branch);
265            }
266            
267            public int getConditionSize() {
268                    return ((jumps == null) ? 0 : jumps.size()) + ((switches == null) ? 0 :switches.size());
269            }
270            
271            public Object getConditionData(int index)
272            {
273                    Object branchData = null;
274                    int jumpsSize = (jumps == null) ? 0 : jumps.size();
275                    int switchesSize = (switches == null) ? 0 :switches.size();
276                    if (index < jumpsSize) 
277                    {
278                            branchData = jumps.get(index);
279                    }
280                    else if (index < jumpsSize + switchesSize)
281                    {
282                            branchData = switches.get(index - jumpsSize);
283                    }
284                    return branchData;
285            }
286            
287            public String getConditionCoverage(int index) {
288                    Object branchData = getConditionData(index);
289                    if (branchData == null)
290                    {
291                            return StringUtil.getPercentValue(1.0);
292                    } 
293                    else if (branchData instanceof JumpData) 
294                    {
295                            JumpData jumpData = (JumpData) branchData;
296                            return StringUtil.getPercentValue(jumpData.getBranchCoverageRate());
297                    }
298                    else
299                    {
300                            SwitchData switchData = (SwitchData) branchData;
301                            return StringUtil.getPercentValue(switchData.getBranchCoverageRate());
302    
303                    }
304            }
305            
306            JumpData getJumpData(int jumpNumber) 
307            {
308                    if (jumps == null) 
309                    {
310                            jumps = new ArrayList();
311                    }
312                    if (jumps.size() <= jumpNumber) 
313                    {
314                            for (int i = jumps.size(); i <= jumpNumber; jumps.add(new JumpData(i++)));
315                    }
316                    return (JumpData) jumps.get(jumpNumber);
317            }
318            
319            SwitchData getSwitchData(int switchNumber, SwitchData data) 
320            {
321                    if (switches == null) 
322                    {
323                            switches = new ArrayList();
324                    }
325                    if (switches.size() < switchNumber) 
326                    {
327                            for (int i = switches.size(); i < switchNumber; switches.add(new SwitchData(i++)));
328                    }
329                    if (switches.size() == switchNumber) 
330                            if (data != null)
331                                    switches.add(data);
332                            else
333                                    switches.add(new SwitchData(switchNumber));
334                    return (SwitchData) switches.get(switchNumber);
335            }
336    
337    }