001package org.andromda.maven.plugin.cartridge; 002 003import java.io.File; 004import java.io.IOException; 005import java.io.PrintWriter; 006import java.io.StringWriter; 007import java.util.ArrayList; 008import java.util.Collection; 009import junit.framework.AssertionFailedError; 010import junit.framework.Test; 011import junit.framework.TestListener; 012import org.apache.commons.io.FileUtils; 013 014/** 015 * Formats the cartridge test results into the correct format. 016 * 017 * @author Chad Brandon 018 * @author Bob Fields 019 */ 020public class CartridgeTestFormatter 021 implements TestListener 022{ 023 /** 024 * Stores the report file location. 025 */ 026 private File reportFile; 027 028 /** 029 * Stores the contents of the report. 030 */ 031 private StringWriter report; 032 033 /** 034 * The print writer for the report. 035 */ 036 private PrintWriter reportWriter; 037 038 /** 039 * Ignore test failures, just show failure messages 040 */ 041 private boolean testFailureIgnore = false; 042 043 /** 044 * 045 */ 046 public CartridgeTestFormatter() 047 { 048 this.report = new StringWriter(); 049 this.reportWriter = new PrintWriter(this.report); 050 } 051 052 /** 053 * Sets the file that will contain the report results (i.e. 054 * the results of the cartridge test run). 055 * 056 * @param reportFile the file to which the report output will be written. 057 */ 058 public void setReportFile(final File reportFile) 059 { 060 this.reportFile = reportFile; 061 } 062 063 /** 064 * Keeps track of the number of errors. 065 */ 066 private int numberOfErrors = 0; 067 068 /** 069 * @see junit.framework.TestListener#addError(junit.framework.Test, Throwable) 070 */ 071 public void addError( 072 Test test, 073 Throwable throwable) 074 { 075 this.numberOfErrors++; 076 this.collectFailure( 077 test, 078 throwable); 079 } 080 081 /** 082 * Keeps track of the number of failures. 083 */ 084 private int numberOfFailures = 0; 085 086 /** 087 * @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError) 088 */ 089 public void addFailure( 090 Test test, 091 AssertionFailedError failure) 092 { 093 this.numberOfFailures++; 094 this.collectFailure( 095 test, 096 failure); 097 } 098 099 /** 100 * @see junit.framework.TestListener#endTest(junit.framework.Test) 101 */ 102 public void endTest(Test test) 103 { 104 } 105 106 /** 107 * Keeps track of the number of tests run. 108 */ 109 private int numberOfTests = 0; 110 111 /** 112 * @see junit.framework.TestListener#startTest(junit.framework.Test) 113 */ 114 public void startTest(Test test) 115 { 116 this.numberOfTests++; 117 } 118 119 /** 120 * Stores the start time of the test suite 121 */ 122 private long startTime = 0; 123 124 /** 125 * Stores the new line separator. 126 */ 127 private static final String newLine = System.getProperty("line.separator"); 128 129 /** 130 * The testsuite started. 131 * @param name 132 */ 133 public void startTestSuite(final String name) 134 { 135 startTime = System.currentTimeMillis(); 136 this.reportWriter.println("-------------------------------------------------------------------------------"); 137 this.reportWriter.println(name + " Test Suite"); 138 this.reportWriter.println("-------------------------------------------------------------------------------"); 139 } 140 141 /** 142 * Adds a failure to the current <code>failures</code> 143 * collection (these are rendered at the end of test suite 144 * execution). 145 * 146 * @param test the actual test. 147 * @param throwable the failure information. 148 */ 149 private void collectFailure( 150 Test test, 151 Throwable throwable) 152 { 153 this.failures.add(new Failure( 154 test, 155 throwable)); 156 } 157 158 private Collection<Failure> failures = new ArrayList<Failure>(); 159 160 /** 161 * Signifies the test suite ended and returns the summary of the 162 * test. 163 * 164 * @param test the test suite being run. 165 * @return the test summary. 166 */ 167 String endTestSuite(Test test) 168 { 169 final double elapsed = ((System.currentTimeMillis() - this.startTime) / 1000.0); 170 final StringBuilder summary = new StringBuilder("Tests: " + String.valueOf(this.numberOfTests) + ", "); 171 summary.append("Failures: ").append(String.valueOf(this.numberOfFailures)).append(", "); 172 summary.append("Errors: ").append(String.valueOf(this.numberOfErrors)).append(", "); 173 summary.append("Time elapsed: ").append(elapsed).append(" sec"); 174 summary.append(newLine); 175 this.reportWriter.print(summary); 176 if (this.numberOfFailures > 0) 177 { 178 this.reportWriter.println("Failures: " + this.numberOfFailures); 179 this.reportWriter.println("-------------------------------------------------------------------------------"); 180 int ctr = 1; 181 for (final Failure failure : this.failures) 182 { 183 final Throwable information = failure.information; 184 if (information instanceof AssertionFailedError) 185 { 186 FileComparator comparator = (FileComparator)failure.test; 187 this.reportWriter.println(ctr + ") " + comparator.getActualFile()); 188 } 189 } 190 this.reportWriter.println("-------------------------------------------------------------------------------"); 191 this.reportWriter.println(); 192 } 193 194 for (final Failure failure : this.failures) 195 { 196 FileComparator comparator = (FileComparator) failure.test; 197 final Throwable information = failure.information; 198 if (information instanceof AssertionFailedError) 199 { 200 this.reportWriter.println("FAILURE: " + comparator.getActualFile()); 201 this.reportWriter.println(failure.information.getMessage()); 202 } 203 else 204 { 205 this.reportWriter.println("ERROR:"); 206 information.printStackTrace(this.reportWriter); 207 } 208 this.reportWriter.println(); 209 } 210 211 if (this.reportFile != null) 212 { 213 try 214 { 215 FileUtils.writeStringToFile(this.reportFile, report.toString()); 216 } 217 catch (IOException exception) 218 { 219 if (isTestFailureIgnore()) 220 { 221 this.reportWriter.println(exception); 222 } 223 else 224 { 225 throw new RuntimeException(exception); 226 } 227 } 228 } 229 return summary.toString(); 230 } 231 232 /** 233 * Stores the information about a test failure. 234 */ 235 private static final class Failure 236 { 237 Test test; 238 Throwable information; 239 240 Failure( 241 final Test test, 242 final Throwable information) 243 { 244 this.test = test; 245 this.information = information; 246 } 247 } 248 249 /** 250 * @return the testFailureIgnore 251 */ 252 public boolean isTestFailureIgnore() 253 { 254 return this.testFailureIgnore; 255 } 256 257 /** 258 * @param testFailureIgnore the testFailureIgnore to set 259 */ 260 public void setTestFailureIgnore(boolean testFailureIgnore) 261 { 262 this.testFailureIgnore = testFailureIgnore; 263 } 264}