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 }