001 /**
002 * www.jcoverage.com
003 * Copyright (C)2003 jcoverage ltd.
004 *
005 * This file is part of jcoverage.
006 *
007 * jcoverage is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published
009 * by the Free Software Foundation; either version 2 of the License,
010 * or (at your option) any later version.
011 *
012 * jcoverage is distributed in the hope that it will be useful, but
013 * WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with jcoverage; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020 * USA
021 *
022 */
023 package com.jcoverage.coverage.reporting.collation;
024
025 import java.util.ArrayList;
026 import java.util.Comparator;
027 import java.util.HashSet;
028 import java.util.Iterator;
029 import java.util.List;
030 import java.util.Map.Entry;
031 import java.util.Map;
032 import java.util.Set;
033 import java.util.SortedSet;
034 import java.util.TreeSet;
035
036 import org.apache.log4j.Logger;
037
038 import com.jcoverage.coverage.Instrumentation;
039 import com.jcoverage.reporting.AbstractPage;
040 import com.jcoverage.reporting.Line;
041 import com.jcoverage.reporting.LineCategory;
042 import com.jcoverage.reporting.Page;
043
044 /**
045 * This class implements a page detailing the coverage results of a
046 * single java source file.
047 */
048 public class JavaFilePage extends AbstractPage implements Page {
049
050 static Logger logger=Logger.getLogger(JavaFilePage.class);
051
052 /**
053 * We can receive multiple instrumentation contributions, since a
054 * single java source file can contain multiple classes (although
055 * strictly only one of these can be declared <code>public</code>).
056 */
057 Set instrumentations=new HashSet();
058
059 /**
060 * The line that summarizes this detail page. We prefer not to
061 * duplicate information- it's either in the summary line or in this
062 * page, not both.
063 */
064 JavaFileLine masterLine;
065
066 /**
067 * This set is important for ordering all the coverage lines as they
068 * come in- the algorithm that highlights uncovered lines is
069 * dependent on all the lines being in order.
070 */
071 SortedSet coverageUnion=new TreeSet(new Comparator() {
072 public int compare(Object o1,Object o2) {
073 int i1=((Integer)((Map.Entry)o1).getKey()).intValue();
074 int i2=((Integer)((Map.Entry)o2).getKey()).intValue();
075 if (i1<i2) {
076 return -1;
077 } else {
078 return 1;
079 }
080 }
081 });
082
083 public JavaFilePage() {
084 super("File");
085 }
086
087 public Set getSourceFileLineCoverageSet() {
088 return coverageUnion;
089 }
090
091 public JavaFileLine getJavaFileLine() {
092 return masterLine;
093 }
094
095 /**
096 * We want to know which of the lines are valid, because we don't
097 * want to count lines that are impossible to reach (blank lines,
098 * braces, import statements, method headers, etc..) in the coverage
099 * calculations and highlighting.
100 */
101 Set validSourceLines=new HashSet();
102
103 /**
104 * We add instrumentation to this instance, so we can work out which lines are hit and which are not.
105 */
106 public void addInstrumentation(Instrumentation instrumentation) {
107 if(logger.isDebugEnabled()) {
108 logger.debug("Adding instrumentation of "+instrumentation.getCoverage().size()+" valid lines to "+masterLine.getClassName());
109 }
110
111 instrumentations.add(instrumentation);
112 coverageUnion.addAll(instrumentation.getCoverage().entrySet());
113
114 if(logger.isDebugEnabled()) {
115 logger.debug("Coverage union is now "+coverageUnion.size()+" valid lines long, coverage is reported at "+getLineCoverageRate());
116 }
117 validSourceLines.addAll(instrumentation.getSourceLineNumbers());
118 }
119
120 /**
121 * This method overrides {@link
122 * com.jcoverage.reporting.AbstractPage#setMasterLine(com.jcoverage.reporting.Line)} so that
123 * we have convenient access to our master line, and don't have to
124 * constantly cast it.
125 */
126 public void setMasterLine(Line masterLine) {
127 super.setMasterLine(masterLine);
128 this.masterLine=(JavaFileLine)masterLine;
129 }
130
131 public Set getValidSourceLines() {
132 return validSourceLines;
133 }
134
135 public int getSourceLinesCount() {
136 int sourceLines=0;
137 for (Iterator it=instrumentations.iterator();it.hasNext();) {
138 sourceLines+=((Instrumentation)it.next()).getSourceLineNumbers().size();
139 }
140 return sourceLines;
141 }
142
143 public double getLineCoverageRate() {
144 int sourceLines=getSourceLinesCount();
145 if (sourceLines==0) {
146 return 0d;
147 } else {
148 return (double)coverageUnion.size()/sourceLines;
149 }
150 }
151
152 public double getBranchCoverageRate() {
153 if(getLineCoverageRate()==0d) {
154 return 0d;
155 }
156
157 double total=0d;
158
159 Iterator i=instrumentations.iterator();
160 while(i.hasNext()) {
161 total+=((Instrumentation)i.next()).getBranchCoverageRate();
162 }
163
164 return total/instrumentations.size();
165 }
166 }