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 }