001package org.andromda.maven.plugin.translationlibrary;
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 translation-library test results into the correct format.
016 *
017 * @author Chad Brandon
018 */
019public class TranslationLibraryTestFormatter
020    implements TestListener
021{
022    /**
023     * Stores the report file location.
024     */
025    private File reportFile;
026
027    /**
028     * Stores the contents of the report.
029     */
030    private StringWriter report;
031
032    /**
033     * The print writer for the report.
034     */
035    private PrintWriter reportWriter;
036
037    /**
038     *
039     */
040    public TranslationLibraryTestFormatter()
041    {
042        this.report = new StringWriter();
043        this.reportWriter = new PrintWriter(this.report);
044    }
045
046    /**
047     * Sets the file that will contain the report results (i.e.
048     * the results of the cartridge test run).
049     *
050     * @param reportFile the file to which the report output will be written.
051     */
052    public void setReportFile(final File reportFile)
053    {
054        this.reportFile = reportFile;
055    }
056
057    /**
058     * Keeps track of the number of errors.
059     */
060    private int numberOfErrors = 0;
061
062    /**
063     * @see junit.framework.TestListener#addError(junit.framework.Test, Throwable)
064     */
065    public void addError(
066        Test test,
067        Throwable throwable)
068    {
069        this.numberOfErrors++;
070        this.collectFailure(
071            test,
072            throwable);
073    }
074
075    /**
076     * Keeps track of the number of failures.
077     */
078    private int numberOfFailures = 0;
079
080    /**
081     * @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError)
082     */
083    public void addFailure(
084        Test test,
085        AssertionFailedError failure)
086    {
087        this.numberOfFailures++;
088        this.collectFailure(
089            test,
090            failure);
091    }
092
093    /**
094     * @see junit.framework.TestListener#endTest(junit.framework.Test)
095     */
096    public void endTest(Test test)
097    {
098    }
099
100    /**
101     * Keeps track of the number of tests run.
102     */
103    private int numberOfTests = 0;
104
105    /**
106     * @see junit.framework.TestListener#startTest(junit.framework.Test)
107     */
108    public void startTest(Test test)
109    {
110        this.numberOfTests++;
111    }
112
113    /**
114     * Stores the start time of the test suite
115     */
116    private long startTime = 0;
117
118    /**
119     * Stores the new line separator.
120     */
121    private static final String newLine = System.getProperty("line.separator");
122
123    /**
124     * The testsuite started.
125     * @param name
126     */
127    public void startTestSuite(final String name)
128    {
129        startTime = System.currentTimeMillis();
130        this.reportWriter.println("-------------------------------------------------------------------------------");
131        this.reportWriter.println(name + " Test Suite");
132        this.reportWriter.println("-------------------------------------------------------------------------------");
133    }
134
135    /**
136     * Adds a failure to the current <code>failures</code>
137     * collection (these are rendered at the end of test suite
138     * execution).
139     *
140     * @param type the failure type (error or failure).
141     * @param test the actual test.
142     * @param throwable the failure information.
143     */
144    private void collectFailure(
145        Test test,
146        Throwable throwable)
147    {
148        this.failures.add(new Failure(
149                test,
150                throwable));
151    }
152
153    private Collection<Failure> failures = new ArrayList<Failure>();
154
155    /**
156     * Signifies the test suite ended and returns the summary of the
157     * test.
158     *
159     * @return the test summary.
160     */
161    String endTestSuite()
162    {
163        final double elapsed = ((System.currentTimeMillis() - this.startTime) / 1000.0);
164        final StringBuilder summary = new StringBuilder("Tests: " + this.numberOfTests + ", ");
165        summary.append("Failures: ").append(this.numberOfFailures).append(", ");
166        summary.append("Errors: ").append(this.numberOfErrors).append(", ");
167        summary.append("Time elapsed: ").append(elapsed).append(" sec");
168        summary.append(newLine);
169        summary.append(newLine);
170        this.reportWriter.print(summary);
171
172        for (final Failure failure : this.failures)
173        {
174            final Throwable information = failure.information;
175            if (information instanceof AssertionFailedError)
176            {
177                this.reportWriter.println(failure.information.getMessage());
178            }
179            else
180            {
181                this.reportWriter.println("ERROR:");
182            }
183            information.printStackTrace(this.reportWriter);
184            this.reportWriter.println();
185        }
186
187        if (this.reportFile != null)
188        {
189            try
190            {
191                final File parent = this.reportFile.getParentFile();
192                if (parent != null && !parent.exists())
193                {
194                    parent.mkdirs();
195                }
196                FileUtils.writeStringToFile(this.reportFile, report.toString());
197            }
198            catch (IOException exception)
199            {
200                throw new RuntimeException(exception);
201            }
202        }
203        return summary.toString();
204    }
205
206    /**
207     * Stores the information about a test failure.
208     */
209    private static final class Failure
210    {
211        @SuppressWarnings("unused")
212        Test test;
213        Throwable information;
214
215        Failure(
216            final Test test,
217            final Throwable information)
218        {
219            this.test = test;
220            this.information = information;
221        }
222    }
223}