001 /* 002 * Created on Jun 6, 2007 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2007-2009 the original author or authors. 014 */ 015 package org.fest.swing.junit.ant; 016 017 import static org.apache.tools.ant.taskdefs.optional.junit.XMLConstants.*; 018 019 import java.io.OutputStream; 020 021 import junit.framework.AssertionFailedError; 022 import junit.framework.Test; 023 024 import org.apache.tools.ant.BuildException; 025 import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter; 026 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest; 027 import org.fest.swing.junit.xml.XmlDocument; 028 import org.fest.swing.junit.xml.XmlNode; 029 030 /** 031 * Understands a copy of the original <code>XMLJUnitResultFormatter</code>, with flexibility for extension. 032 * 033 * @author Alex Ruiz 034 */ 035 public class XmlJUnitResultFormatter implements JUnitResultFormatter { 036 037 private XmlNode xmlRoot; 038 039 private OutputStream out; // where to write the log to 040 041 private final TestCollection tests; 042 043 private final SuiteXmlNodeWriter suiteXmlNodeWriter; 044 private final EnvironmentXmlNodeWriter environmentXmlNodeWriter; 045 private final TestXmlNodeWriter testXmlNodeWriter; 046 047 private final XmlOutputWriter xmlOutputWriter; 048 049 /** 050 * Creates a new </code>{@link XmlJUnitResultFormatter}</code>. 051 */ 052 public XmlJUnitResultFormatter() { 053 tests = new TestCollection(); 054 suiteXmlNodeWriter = new SuiteXmlNodeWriter(); 055 environmentXmlNodeWriter = new EnvironmentXmlNodeWriter(); 056 testXmlNodeWriter = new TestXmlNodeWriter(); 057 xmlOutputWriter = new XmlOutputWriter(); 058 } 059 060 // for testing only 061 final TestCollection tests() { return tests; } 062 063 /** 064 * Sets the stream the formatter is supposed to write its results to. 065 * @param out the output stream to use. 066 */ 067 public final void setOutput(OutputStream out) { 068 this.out = out; 069 } 070 071 /** 072 * This is what the test has written to <code>System.out</code>, 073 * @param out the <code>String</code> to write. 074 */ 075 public final void setSystemOutput(String out) { 076 formatOutput(SYSTEM_OUT, out); 077 } 078 079 /** 080 * This is what the test has written to <code>System.err</code>. 081 * @param out the <code>String</code> to write. 082 */ 083 public final void setSystemError(String out) { 084 formatOutput(SYSTEM_ERR, out); 085 } 086 087 private void formatOutput(String type, String output) { 088 xmlRoot.addNewNode(type).addCdata(output); 089 } 090 091 protected final XmlNode xmlRootNode() { return xmlRoot; } 092 093 /** 094 * The whole test suite started. This method starts creation of the XML report. 095 * @param suite the test suite. 096 * @throws ExceptionInInitializerError if the underlying XML document could not be created. 097 */ 098 public final void startTestSuite(JUnitTest suite) { 099 XmlDocument document = new XmlDocument(); 100 xmlRoot = document.newRoot(TESTSUITE); 101 suiteXmlNodeWriter.writeSuiteName(xmlRoot, suite) 102 .writeSuiteProperties(xmlRoot, suite); 103 environmentXmlNodeWriter.writeHostName(xmlRoot) 104 .writeTimestamp(xmlRoot); 105 onStartTestSuite(suite); 106 } 107 108 /** 109 * Hook for subclasses to add extra functionality after the whole test suite started. 110 * @param suite the test suite. 111 */ 112 protected void onStartTestSuite(JUnitTest suite) {} 113 114 /** 115 * The whole test suite ended. This method finishes writing the XML report and writes its contents to this 116 * formatter's <code>{@link OutputStream}</code>. 117 * @param suite the test suite. 118 * @throws BuildException on error. 119 */ 120 public final void endTestSuite(JUnitTest suite) { 121 suiteXmlNodeWriter.writeSuiteStatistics(xmlRoot, suite); 122 if (out == null) return; 123 xmlOutputWriter.write(xmlRoot, out); 124 } 125 126 /** 127 * A new test is started. 128 * @param test the test. 129 */ 130 public final void startTest(Test test) { 131 tests.started(test); 132 } 133 134 /** 135 * A test is finished. 136 * @param test the test. 137 */ 138 public final void endTest(Test test) { 139 if (!tests.wasStarted(test)) startTest(test); 140 XmlNode testNode = xmlNodeForFinished(test); 141 testXmlNodeWriter.writeTestExecutionTime(testNode, tests.startTimeOf(test)); 142 } 143 144 private XmlNode xmlNodeForFinished(Test test) { 145 if (tests.wasFailed(test)) return tests.xmlNodeFor(test); 146 XmlNode newTestXmlNode = testXmlNodeWriter.addNewTestXmlNode(xmlRoot, test); 147 tests.addXmlNode(test, newTestXmlNode); 148 return newTestXmlNode; 149 } 150 151 /** 152 * A test failed. 153 * @param test the test. 154 * @param failedAssertion the failed assertion. 155 */ 156 public final void addFailure(Test test, AssertionFailedError failedAssertion) { 157 addFailure(test, (Throwable)failedAssertion); 158 } 159 160 /** 161 * A test failed. 162 * @param test the test. 163 * @param error the exception. 164 */ 165 public final void addFailure(Test test, Throwable error) { 166 XmlNode errorXmlNode = formatError(FAILURE, test, error); 167 onFailureOrError(test, error, errorXmlNode); 168 } 169 170 /** 171 * An error occurred while running the test. 172 * @param test the test. 173 * @param error the error. 174 */ 175 public final void addError(Test test, Throwable error) { 176 XmlNode errorXmlNode = formatError(ERROR, test, error); 177 onFailureOrError(test, error, errorXmlNode); 178 } 179 180 private XmlNode formatError(String type, Test test, Throwable error) { 181 if (test != null) { 182 endTest(test); 183 tests.failed(test); 184 } 185 XmlNode errorXmlNode = xmlForFailed(test).addNewNode(type); 186 writeErrorAndStackTrace(error, errorXmlNode); 187 return errorXmlNode; 188 } 189 190 private XmlNode xmlForFailed(Test test) { 191 if (test != null) return tests.xmlNodeFor(test); 192 return xmlRoot; 193 } 194 195 /** 196 * Writes the stack trace and message of the given error to the given XML node. 197 * @param error the given error. 198 * @param errorXmlNode the XML node to write to. 199 */ 200 protected final void writeErrorAndStackTrace(Throwable error, XmlNode errorXmlNode) { 201 testXmlNodeWriter.writeErrorAndStackTrace(errorXmlNode, error); 202 } 203 204 /** 205 * Hook for subclasses to add extra functionality after a test failure or a test execution error. 206 * @param test the executing test. 207 * @param error the reason of the failure or error. 208 * @param errorXmlNode the XML element containing information about the test failure or error. 209 */ 210 protected void onFailureOrError(Test test, Throwable error, XmlNode errorXmlNode) {} 211 }