/*******************************************************************************
* Copyright (c) 2009, eXXcellent solutions gmbh and others
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*
* Contributors:
* Achim Demelt - initial API and implementation
* Matthias Kappeller - Bug 321064 - No JUnit TestReport created for huge report files
*******************************************************************************/
package org.eclipse.buckminster.junit;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.buckminster.cmdline.Option;
import org.eclipse.buckminster.cmdline.OptionDescriptor;
import org.eclipse.buckminster.cmdline.OptionValueType;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.commands.Launch;
import org.eclipse.buckminster.core.helpers.FileUtils;
import org.eclipse.buckminster.junit.internal.Messages;
import org.eclipse.buckminster.junit.internal.ResultSerializer;
import org.eclipse.buckminster.junit.internal.TestListener;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.junit.JUnitCore;
import org.xml.sax.InputSource;
public class JUnitCommand extends Launch {
private static final OptionDescriptor QUIET_DESCRIPTOR = new OptionDescriptor('q', "quiet", OptionValueType.NONE); //$NON-NLS-1$
private static final OptionDescriptor OUTPUT_DESCRIPTOR = new OptionDescriptor('o', "output", //$NON-NLS-1$
OptionValueType.REQUIRED);
private static final OptionDescriptor TERSE_XML_DESCRIPTOR = new OptionDescriptor(null, "terseXML", //$NON-NLS-1$
OptionValueType.NONE);
private static final OptionDescriptor FLAT_XML_DESCRIPTOR = new OptionDescriptor(null, "flatXML", //$NON-NLS-1$
OptionValueType.NONE);
private static final OptionDescriptor MAX_AWAIT_JUNIT_REPORT_DESCRIPTOR = new OptionDescriptor('t', "maxTimeAwaitJunitReport", //$NON-NLS-1$
OptionValueType.REQUIRED);
private boolean quiet;
private String outputPath;
private boolean terseXML;
private boolean flatXML;
private int maxAwaitJunitReport = 10;
@Override
protected void getOptionDescriptors(List<OptionDescriptor> appendHere) throws Exception {
super.getOptionDescriptors(appendHere);
appendHere.add(QUIET_DESCRIPTOR);
appendHere.add(OUTPUT_DESCRIPTOR);
appendHere.add(TERSE_XML_DESCRIPTOR);
appendHere.add(FLAT_XML_DESCRIPTOR);
appendHere.add(MAX_AWAIT_JUNIT_REPORT_DESCRIPTOR);
}
@Override
protected void handleOption(Option option) throws Exception {
super.handleOption(option);
if (option.is(QUIET_DESCRIPTOR))
quiet = true;
else if (option.is(OUTPUT_DESCRIPTOR))
outputPath = option.getValue();
else if (option.is(TERSE_XML_DESCRIPTOR))
terseXML = true;
else if (option.is(FLAT_XML_DESCRIPTOR))
flatXML = true;
else if (option.is(MAX_AWAIT_JUNIT_REPORT_DESCRIPTOR)) {
maxAwaitJunitReport = Integer.valueOf(option.getValue()).intValue();
}
}
@Override
protected int internalRun(IProgressMonitor monitor) throws Exception {
TestListener listener = new TestListener(quiet);
JUnitCore.addTestRunListener(listener);
try {
int result = super.internalRun(monitor);
if (outputPath != null)
exportTestRunSession(listener);
return result;
} finally {
JUnitCore.removeTestRunListener(listener);
}
}
/*
* This method is basically copied from JUnitModel#exportTestRunSession in
* order to avoid using internal API.
*/
private void exportTestRunSession(TestListener listener) throws Exception {
// bug #321064 - No JUnit TestReport created for huge report files
try {
listener.waitForFinish(maxAwaitJunitReport, TimeUnit.SECONDS);
} catch (InterruptedException e) {
CorePlugin.getLogger().warning(e, Messages.JUnitCommand_Export_interrupted);
Thread.interrupted();
}
// bug #292376 - JUnit reporting fails if output path does not exist
File parentFile = new File(outputPath).getParentFile();
if (parentFile != null)
FileUtils.createDirectory(parentFile, new NullProgressMonitor());
OutputStream out = new BufferedOutputStream(new FileOutputStream(outputPath));
Transformer transformer = TransformerFactory.newInstance().newTransformer();
InputSource inputSource = new InputSource();
SAXSource source = new SAXSource(new ResultSerializer(listener, getRawStdOut(), getRawStdErr(), terseXML, flatXML), inputSource);
StreamResult result = new StreamResult(out);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
/*
* Bug in Xalan: Only indents if proprietary property
* org.apache.xalan.templates.OutputProperties.S_KEY_INDENT_AMOUNT is
* set.
*
* Bug in Xalan as shipped with J2SE 5.0: Does not read the
* indent-amount property at all >:-(.
*/
try {
transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (IllegalArgumentException e) {
// no indentation today...
}
transformer.transform(source, result);
}
}