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 */
023package com.jcoverage.coverage.reporting.collation;
024
025import java.util.ArrayList;
026import java.util.Comparator;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.List;
030import java.util.Map.Entry;
031import java.util.Map;
032import java.util.Set;
033import java.util.SortedSet;
034import java.util.TreeSet;
035
036import org.apache.log4j.Logger;
037
038import com.jcoverage.coverage.Instrumentation;
039import com.jcoverage.reporting.AbstractPage;
040import com.jcoverage.reporting.Line;
041import com.jcoverage.reporting.LineCategory;
042import com.jcoverage.reporting.Page;
043
044/**
045 * This class implements a page detailing the coverage results of a
046 * single java source file.
047 */
048public 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}