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
025package net.sourceforge.cobertura.coveragedata;
026
027import java.io.Serializable;
028import java.util.ArrayList;
029import java.util.List;
030
031import net.sourceforge.cobertura.CoverageIgnore;
032import net.sourceforge.cobertura.util.StringUtil;
033
034@CoverageIgnore
035public class LineData
036                implements Comparable<Object>, CoverageData, Serializable
037{
038        private static final long serialVersionUID = 4;
039
040        private long hits;
041        private List<JumpData> jumps;
042        private List<SwitchData> switches;
043        private final int lineNumber;
044        private String methodDescriptor;
045        private String methodName;
046
047        LineData(int lineNumber) {
048                this(lineNumber, null, null);
049        }
050
051        LineData(int lineNumber, String methodName, String methodDescriptor) {
052                this.hits = 0;
053                this.jumps = null;
054                this.lineNumber = lineNumber;
055                this.methodName = methodName;
056                this.methodDescriptor = methodDescriptor;
057        }
058        
059        /**
060         * This is required because we implement Comparable.
061         */
062        public int compareTo(Object o) {
063                if (!o.getClass().equals(LineData.class))
064                        return Integer.MAX_VALUE;
065                return this.lineNumber - ((LineData)o).lineNumber;
066        }
067
068        public boolean equals(Object obj) {
069                if (this == obj)
070                        return true;
071                if ((obj == null) || !(obj.getClass().equals(this.getClass())))
072                        return false;
073
074                LineData lineData = (LineData)obj;
075                return (this.hits == lineData.hits)
076                                && ((this.jumps == lineData.jumps) || ((this.jumps != null) && (this.jumps.equals(lineData.jumps))))
077                                && ((this.switches == lineData.switches) || ((this.switches != null) && (this.switches.equals(lineData.switches))))
078                                && (this.lineNumber == lineData.lineNumber)
079                                && (this.methodDescriptor.equals(lineData.methodDescriptor))
080                                && (this.methodName.equals(lineData.methodName));
081        }
082
083        public double getBranchCoverageRate() {
084                if (getNumberOfValidBranches() == 0)
085                        return 1d;
086                return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches();
087        }
088
089        public String getConditionCoverage() {
090                StringBuffer ret = new StringBuffer();
091                if (getNumberOfValidBranches() == 0) {
092                        ret.append(StringUtil.getPercentValue(1.0));
093                } else {
094                        ret.append(StringUtil.getPercentValue(getBranchCoverageRate()));
095                        ret.append(" (").append(getNumberOfCoveredBranches()).append("/").append(getNumberOfValidBranches()).append(")");
096                }
097                return ret.toString();
098        }
099        
100        public long getHits() {
101        return hits;
102        }
103
104        synchronized public boolean isCovered() {
105                return (getHits() > 0) && ((getNumberOfValidBranches() == 0) || ((1.0 - getBranchCoverageRate()) < 0.0001));
106        }
107        
108        public double getLineCoverageRate() {
109                return (getHits() > 0) ? 1 : 0;
110        }
111
112        public int getLineNumber() {
113                return lineNumber;
114        }
115
116        public String getMethodDescriptor() {
117                return methodDescriptor;
118        }
119
120        public String getMethodName() {
121                return methodName;
122        }
123
124        public int getNumberOfCoveredLines()
125        {
126                return (getHits() > 0) ? 1 : 0;
127        }
128
129        public int getNumberOfValidBranches() {
130                int ret = 0;
131                if (jumps != null)
132                        for (int i = jumps.size() - 1; i >= 0; i--)
133                                ret += ((JumpData) jumps.get(i)).getNumberOfValidBranches();
134                if (switches != null)
135                        for (int i = switches.size() - 1; i >= 0; i--)
136                                ret += ((SwitchData) switches.get(i)).getNumberOfValidBranches();
137                return ret;
138        }
139        
140        public int getNumberOfCoveredBranches() {
141                int ret = 0;
142                if (jumps != null)
143                        for (int i = jumps.size() - 1; i >= 0; i--)
144                                ret += ((JumpData) jumps.get(i)).getNumberOfCoveredBranches();
145                if (switches != null)
146                        for (int i = switches.size() - 1; i >= 0; i--)
147                                ret += ((SwitchData) switches.get(i)).getNumberOfCoveredBranches();
148                return ret;
149        }
150
151        public int getNumberOfValidLines() {
152                return 1;
153        }
154
155        public int hashCode() {
156                return this.lineNumber;
157        }
158
159        public boolean hasBranch() {
160                return (jumps != null) || (switches != null);
161        }
162
163        synchronized public void merge(CoverageData coverageData) {
164                LineData lineData = (LineData)coverageData;
165                this.hits += lineData.hits;
166                if (lineData.jumps != null)
167                        if (this.jumps == null) 
168                                this.jumps = lineData.jumps;
169                        else
170                        {
171                                for (int i = Math.min(this.jumps.size(), lineData.jumps.size()) - 1; i >= 0; i--)
172                                        ((JumpData) this.jumps.get(i)).merge((JumpData) lineData.jumps.get(i));
173                                for (int i = Math.min(this.jumps.size(), lineData.jumps.size()); i < lineData.jumps.size(); i++) 
174                                        this.jumps.add(lineData.jumps.get(i));
175                        }
176                if (lineData.switches != null)
177                        if (this.switches == null) 
178                                this.switches = lineData.switches;
179                        else
180                        {
181                                for (int i = Math.min(this.switches.size(), lineData.switches.size()) - 1; i >= 0; i--)
182                                        ((SwitchData) this.switches.get(i)).merge((SwitchData) lineData.switches.get(i));
183                                for (int i = Math.min(this.switches.size(), lineData.switches.size()); i < lineData.switches.size(); i++) 
184                                        this.switches.add(lineData.switches.get(i));
185                        }
186                if (lineData.methodName != null)
187                        this.methodName = lineData.methodName;
188                if (lineData.methodDescriptor != null)
189                        this.methodDescriptor = lineData.methodDescriptor;              
190        }
191
192        void addJump(int jumpNumber) {
193                getJumpData(jumpNumber);
194        }
195
196        void addSwitch(int switchNumber, int min, int max, int maxBranches) {
197                SwitchData sd = getSwitchData(switchNumber, new SwitchData(switchNumber, min, max, maxBranches));
198                if (sd.getMaxBranches() > maxBranches) {
199                        sd.setMaxBranches(maxBranches);
200                }
201        } 
202
203        void setMethodNameAndDescriptor(String name, String descriptor) {
204                this.methodName = name;
205                this.methodDescriptor = descriptor;
206        }
207
208        void touch(int new_hits) {
209                this.hits += new_hits;
210        }
211        
212        void touchJump(int jumpNumber, boolean branch, int hits) {
213                getJumpData(jumpNumber).touchBranch(branch,hits);
214        }
215        
216        void touchSwitch(int switchNumber, int branch,int hits) {
217                getSwitchData(switchNumber, null).touchBranch(branch,hits);
218        }
219        
220        public int getConditionSize() {
221                return ((jumps == null) ? 0 : jumps.size()) + ((switches == null) ? 0 :switches.size());
222        }
223        
224        public Object getConditionData(int index) {
225                Object branchData = null;               
226                int jumpsSize = (jumps == null) ? 0 : jumps.size();
227                int switchesSize = (switches == null) ? 0 :switches.size();
228                if (index < jumpsSize) 
229                {
230                        branchData = jumps.get(index);
231                }
232                else if (index < jumpsSize + switchesSize)
233                {
234                        branchData = switches.get(index - jumpsSize);
235                }
236                return branchData;
237        }
238        
239        public String getConditionCoverage(int index) {
240                Object branchData = getConditionData(index);
241                if (branchData == null)
242                {
243                        return StringUtil.getPercentValue(1.0);
244                } else if (branchData instanceof JumpData) {
245                        JumpData jumpData = (JumpData) branchData;
246                        return StringUtil.getPercentValue(jumpData.getBranchCoverageRate());
247                } else {
248                        SwitchData switchData = (SwitchData) branchData;
249                        return StringUtil.getPercentValue(switchData.getBranchCoverageRate());
250
251                }
252        }
253        
254        synchronized JumpData getJumpData(int jumpNumber) {
255                if (jumps == null) {
256                        jumps = new ArrayList<JumpData>();
257                }
258                if (jumps.size() <= jumpNumber) {
259                        for (int i = jumps.size(); i <= jumpNumber; jumps.add(new JumpData(i++)));
260                }
261                return jumps.get(jumpNumber);
262        }
263        
264        synchronized SwitchData getSwitchData(int switchNumber, SwitchData data) {
265                if (switches == null) {
266                        switches = new ArrayList<SwitchData>();
267                }
268                if (switches.size() < switchNumber) 
269                {
270                        for (int i = switches.size(); i < switchNumber; switches.add(new SwitchData(i++, Integer.MAX_VALUE )));
271                }
272                if (switches.size() == switchNumber) {
273                        if (data != null) {
274                                switches.add(data);
275                        } else {
276                                switches.add(new SwitchData(switchNumber, Integer.MAX_VALUE));
277                        }
278                }
279                return (SwitchData) switches.get(switchNumber); 
280        }
281
282}