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.html;
024    
025    import java.io.*;
026    import java.util.*;
027    
028    import org.apache.log4j.Logger;
029    
030    import com.jcoverage.coverage.reporting.collation.JavaFilePage;
031    import com.jcoverage.reporting.html.HtmlFormatHelper;
032    import com.jcoverage.reporting.html.Writable;
033    
034    /**
035     *
036     */
037    public class SourceTable implements Writable {
038      
039      static Logger logger=Logger.getLogger(SourceTable.class);
040      
041      File sourceFile;
042      JavaFilePage page;
043    
044      public SourceTable(File sourceFile,JavaFilePage page) {
045        this.sourceFile=sourceFile;
046        this.page=page;
047      }
048    
049      public void writeTo(PrintWriter writer) {
050    
051        writer.println("<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\" width=\"85%\">");
052        writer.print("<tr>");
053        writer.print("<th>Line</th>");
054        writer.print("<th>Hits</th>");
055        writer.print("<th class=\"remainder\">Source</th>");
056        writer.println("</tr>");
057    
058        int lineNo=1;             // Java source code lines are 1-based
059    
060        try {
061          BufferedReader source=new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile)));
062    
063          Iterator coverage=page.getSourceFileLineCoverageSet().iterator();
064    
065          while(coverage.hasNext()) {
066            Map.Entry entry=(Map.Entry)coverage.next();
067            int nextLineNo=((Integer)entry.getKey()).intValue();
068    
069            while (lineNo<nextLineNo) {
070              String line=source.readLine();
071              if (line==null) {
072                break;
073              }
074              writeRow(writer,page,lineNo,0,indentSource(line));
075              lineNo++;
076            }
077                
078            if (lineNo==nextLineNo) {
079              String line=source.readLine();
080              if (line==null) {
081                // As above
082                break;
083              }
084              writeRow(writer,page,nextLineNo,((Long)entry.getValue()).longValue(),indentSource(line));
085              lineNo++;
086            }
087    
088          }
089            
090          while (true) {
091            String remainder=source.readLine();
092            if (remainder==null) {
093              // We have come to the end of the file.
094              break;
095            }
096            writeRow(writer,page,lineNo,0,indentSource(remainder));
097            lineNo++;
098          }
099    
100        } catch (Exception ex) {
101          writer.println("<p>Failed to read java source file: ");
102          writer.println("<pre>");
103          writer.println(ex.toString());
104          writer.println("</pre>");
105        }
106    
107        writer.println("</table>");
108      }
109      
110      private void writeRow(PrintWriter writer,JavaFilePage page,int lineNo,long hits,String line) {
111        String cssClass=(lineNo%2==0?"yin":"yang");
112        boolean validLine=page.getValidSourceLines().contains(new Integer(lineNo));
113        if (validLine && hits==0) {
114          cssClass="highlight";
115        }
116    
117        writer.print("<tr class=\""+cssClass+"\">");
118    
119        writeCell(writer,String.valueOf(lineNo),"lineno");
120    
121        if (validLine) {
122          writeCell(writer,String.valueOf(hits),"hits");
123        } else {
124          writeCell(writer," ","hits");
125        }
126    
127        writeCell(writer,"<tt>"+line+"</tt>","code");
128        writer.println("</tr>");
129      }
130    
131      void writeCell(PrintWriter writer,String content,String cssClass) {
132        writer.print("<td class=\""+cssClass+"\">"+content+"</td>");
133      }
134    
135      /**
136       * @return a String that has leading spaces converted into non-breaking spaces.
137       */
138      static String indentSource(String line) {
139        StringBuffer sb=new StringBuffer(HtmlFormatHelper.replaceCharacterEntities(HtmlFormatHelper.untabify(line,HtmlFormatHelper.TAB_WIDTH)));
140        StringBuffer newsb=new StringBuffer();
141        int i=0;
142        while(i<sb.length() && sb.charAt(i)==' ') {
143          i++;
144          newsb.append(" ");
145        }
146        newsb.append(sb.substring(i));
147    
148        // For CSS rendering reasons, we always like to have something in the table cell, even if it's just a space.
149        if (newsb.length()==0) {
150          newsb.append(" ");
151        }
152    
153        return newsb.toString();
154      }
155    
156    }