blob: d64fcec55b817041e99624b2b800b528c61ee03c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.vxquery.xtest;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.vxquery.xtest.TestCaseResult.State;
public class HTMLFileReporterImpl implements ResultReporter {
private List<TestCaseResult> results;
private int count;
private int userErrors;
private int internalErrors;
private Map<Class<?>, Integer> exDistribution;
private Map<TestCaseResult.State, Integer> stDistribution;
private long startTime;
private long endTime;
private PrintWriter out;
private File reportFile;
public HTMLFileReporterImpl(File file) {
results = new ArrayList<>();
count = 0;
userErrors = 0;
internalErrors = 0;
startTime = -1;
exDistribution = new HashMap<>();
stDistribution = new HashMap<>();
reportFile = file;
}
@Override
public void reportResult(TestCaseResult result) {
results.add(result);
endTime = System.currentTimeMillis();
if (startTime < 0) {
startTime = endTime;
}
if (result.error()) {
if (result.userError()) {
++userErrors;
} else {
++internalErrors;
Integer internalCount = exDistribution.get(result.error.getClass());
if (internalCount == null) {
internalCount = 0;
}
internalCount++;
exDistribution.put(result.error.getClass(), internalCount);
}
}
Integer stCount = stDistribution.get(result.state);
if (stCount == null) {
stCount = 0;
}
stCount++;
stDistribution.put(result.state, stCount);
++count;
}
@Override
public void close() {
if (reportFile != null) {
try {
out = new PrintWriter(reportFile);
writeHTML(out, createResultDir(reportFile));
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static File createResultDir(File file) {
String fileName = file.getName();
int dot = file.getName().lastIndexOf('.');
String resultDirName = (dot < 0 ? fileName : fileName.substring(0, dot)) + "_results";
return file.getParent() != null ? new File(file.getParent() + File.separator + resultDirName)
: new File(resultDirName);
}
public void writeHTML(PrintWriter out) {
writeHTML(out, null);
}
public void writeHTML(PrintWriter out, File resultDir) {
long start = System.currentTimeMillis();
out.println("<html><body>");
writeSummary(out, count, userErrors, internalErrors, startTime, endTime);
out.println("<hl>");
writeStateDistribution(out, stDistribution);
out.println("<hl>");
writeExceptionDistribution(out, exDistribution);
out.println("<hl>");
writeResults(out, resultDir, results);
out.println("</body></html>");
System.err.println("HTML generation time: " + (System.currentTimeMillis() - start));
}
private static void writeSummary(PrintWriter out, int count, int userErrors, int internalErrors, long startTime,
long endTime) {
out.println("<table>");
out.println("<tr><td>Test Count</td><td>");
out.println(count);
out.println("</td></tr>");
out.println("<tr><td>Test Errors</td><td>");
out.println(userErrors);
out.println("</td></tr>");
out.println("<tr><td>Test Failures</td><td>");
out.println(internalErrors);
out.println("</td></tr>");
out.println("<tr><td>Total time</td><td>");
out.println(endTime - startTime);
out.println("</td></tr>");
out.println("</table>");
}
private static void writeExceptionDistribution(PrintWriter out, Map<Class<?>, Integer> exDistribution) {
out.println("<table>");
List<Entry<Class<?>, Integer>> entryList = new ArrayList<>(exDistribution.entrySet());
Comparator<Entry<Class<?>, Integer>> comp = new Comparator<Entry<Class<?>, Integer>>() {
public int compare(Entry<Class<?>, Integer> o1, Entry<Class<?>, Integer> o2) {
return o1.getKey().getName().compareTo(o2.getKey().getName());
}
};
Collections.sort(entryList, comp);
for (Map.Entry<Class<?>, Integer> e : entryList) {
out.println("<tr><td>");
out.println(e.getKey().getName());
out.println("</td><td>");
out.println(e.getValue());
out.println("</td></tr>");
}
out.println("</table>");
}
private static void writeStateDistribution(PrintWriter out, Map<TestCaseResult.State, Integer> stDistribution) {
out.println("<table>");
List<Map.Entry<TestCaseResult.State, Integer>> entryList = new ArrayList<>(stDistribution.entrySet());
Comparator<Map.Entry<TestCaseResult.State, Integer>> comp = new Comparator<Map.Entry<TestCaseResult.State, Integer>>() {
public int compare(Map.Entry<TestCaseResult.State, Integer> o1,
Map.Entry<TestCaseResult.State, Integer> o2) {
return o1.getKey().compareTo(o2.getKey());
}
};
Collections.sort(entryList, comp);
for (Map.Entry<TestCaseResult.State, Integer> e : entryList) {
State key = e.getKey();
out.print("<tr style=\"background: ");
out.println(key.getColor());
out.println(";\"><td>");
out.println(key);
out.println("</td><td>");
out.println(e.getValue());
out.println("</td></tr>");
}
out.println("</table>");
}
private static void writeResults(PrintWriter out, File resultDir, List<TestCaseResult> results) {
ResultManager rfw = new ResultManager(resultDir);
out.println("<table>");
int len = results.size();
for (int i = 0; i < len; ++i) {
TestCaseResult res = results.get(i);
out.print("<tr style=\"background: ");
out.println(res.state.getColor());
out.println(";\"><td>");
out.print(i + 1);
out.print("</td><td><a href=\"");
out.print(res.testCase.getXQueryFile().toURI());
out.print("\">");
String queryDisplayName = res.testCase.getXQueryDisplayName();
out.print(queryDisplayName);
out.print("</a></td><td>");
out.print(res.time);
out.print("</td><td>");
String uri = rfw.writeResult(res, queryDisplayName);
if (uri != null) {
out.print("<a href=\"");
out.print(uri);
out.print("\">");
out.print(res.report);
out.print("</a>");
} else {
out.print(res.report);
}
out.println("</td></tr>");
}
out.println("</table>");
rfw.close();
}
}
/**
* writes results into several HTML files of manageable size
*/
class ResultManager {
/**
* if the length of a file passes this length, a new file will be used
* for the next result
*/
private static final long MAX_LEN = 1000000;
private final File dir;
private File curFile;
private URI curURI;
private FileWriter curFileWriter;
private PrintWriter curPrintWriter;
ResultManager(File dir) {
this.dir = dir;
}
/**
* writes an HTML serialization of a test result into a temp HTML file
* inside the given directory
*
* @param res
* the result data for 1 test case
* @param linkName
* the name of the (internal) HTML link that points to
* the test result inside the HTML file
* @return the full URI that references the test result in the HTML file
*/
String writeResult(TestCaseResult res, String linkName) {
if (dir == null) {
return null;
}
try {
if (curFile == null || curFile.length() > MAX_LEN) {
if (curFile != null) {
writeDocFooter(curPrintWriter);
curPrintWriter.flush();
curFileWriter.close();
} else {
ensureDir(dir);
}
curFile = File.createTempFile("res", ".html", dir);
curFileWriter = new FileWriter(curFile);
curPrintWriter = new PrintWriter(new BufferedWriter(curFileWriter));
curURI = curFile.toURI();
writeDocHeader(curPrintWriter);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
curPrintWriter.println("<a style=\"background: " + res.state.getColor() + "\" name=\"" + linkName
+ "\">&nbsp;&nbsp;&nbsp;</a>");
curPrintWriter.println(linkName);
curPrintWriter.println("<pre>");
if (res.result != null) {
curPrintWriter.println(escape(res.result));
} else {
res.error.printStackTrace(curPrintWriter);
}
curPrintWriter.println("</pre>");
return curURI + "#" + linkName;
}
void close() {
try {
if (curFile != null) {
writeDocFooter(curPrintWriter);
curPrintWriter.flush();
curFileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static void ensureDir(File dir) throws IOException {
if (!dir.isDirectory() && !dir.mkdirs()) {
throw new IOException("could not create dir " + dir);
}
}
private static void writeDocHeader(PrintWriter resOut) {
resOut.println("<html><head><title>results</title>");
resOut.println("<style type=\"text/css\">");
resOut.println("pre {background: #F0F0F0}");
resOut.println("</style></head><body>");
}
private static void writeDocFooter(PrintWriter resOut) {
resOut.println("</body></html>");
}
/* this should not be necessary anymore, when the XQuery serialization
* works right
*/
private static String escape(String s) {
final char[] ca = s.toCharArray();
final int l = ca.length;
int start = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < l; ++i) {
switch (ca[i]) {
case '<':
sb.append(ca, start, i - start);
sb.append("&lt;");
start = i + 1;
break;
case '>':
sb.append(ca, start, i - start);
sb.append("&gt;");
start = i + 1;
break;
case '&':
sb.append(ca, start, i - start);
sb.append("&amp;");
start = i + 1;
break;
}
}
return start > 0 ? sb.toString() : s;
}
}