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    }