pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / test-framework / java / org / apache / lucene / util / LuceneJUnitResultFormatter.java
1 /**
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  */
18
19 package org.apache.lucene.util;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.text.NumberFormat;
26 import java.util.logging.LogManager;
27
28 import junit.framework.AssertionFailedError;
29 import junit.framework.Test;
30
31 import org.apache.lucene.store.LockReleaseFailedException;
32 import org.apache.lucene.store.NativeFSLockFactory;
33 import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
34 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
35 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner;
36 import org.apache.tools.ant.util.FileUtils;
37 import org.apache.tools.ant.util.StringUtils;
38 import org.junit.Ignore;
39
40 /**
41  * Just like BriefJUnitResultFormatter "brief" bundled with ant,
42  * except all formatted text is buffered until the test suite is finished.
43  * At this point, the output is written at once in synchronized fashion.
44  * This way tests can run in parallel without interleaving output.
45  */
46 public class LuceneJUnitResultFormatter implements JUnitResultFormatter {
47   private static final double ONE_SECOND = 1000.0;
48   
49   private static final NativeFSLockFactory lockFactory;
50   
51   /** Where to write the log to. */
52   private OutputStream out;
53   
54   /** Formatter for timings. */
55   private NumberFormat numberFormat = NumberFormat.getInstance();
56   
57   /** Output suite has written to System.out */
58   private String systemOutput = null;
59   
60   /** Output suite has written to System.err */
61   private String systemError = null;
62   
63   /** Buffer output until the end of the test */
64   private ByteArrayOutputStream sb; // use a BOS for our mostly ascii-output
65
66   private static final org.apache.lucene.store.Lock lock;
67
68   static {
69     File lockDir = new File(
70         System.getProperty("tests.lockdir", System.getProperty("java.io.tmpdir")),
71         "lucene_junit_lock");
72     lockDir.mkdirs();
73     if (!lockDir.exists()) {
74       throw new RuntimeException("Could not make Lock directory:" + lockDir);
75     }
76     try {
77       lockFactory = new NativeFSLockFactory(lockDir);
78       lock = lockFactory.makeLock("junit_lock");
79     } catch (IOException e) {
80       throw new RuntimeException(e);
81     }
82   }
83
84   /** Constructor for LuceneJUnitResultFormatter. */
85   public LuceneJUnitResultFormatter() {
86   }
87   
88   /**
89    * Sets the stream the formatter is supposed to write its results to.
90    * @param out the output stream to write to
91    */
92   public void setOutput(OutputStream out) {
93     this.out = out;
94   }
95   
96   /**
97    * @see JUnitResultFormatter#setSystemOutput(String)
98    */
99   /** {@inheritDoc}. */
100   public void setSystemOutput(String out) {
101     systemOutput = out;
102   }
103   
104   /**
105    * @see JUnitResultFormatter#setSystemError(String)
106    */
107   /** {@inheritDoc}. */
108   public void setSystemError(String err) {
109     systemError = err;
110   }
111   
112   
113   /**
114    * The whole testsuite started.
115    * @param suite the test suite
116    */
117   public synchronized void startTestSuite(JUnitTest suite) {
118     if (out == null) {
119       return; // Quick return - no output do nothing.
120     }
121     sb = new ByteArrayOutputStream(); // don't reuse, so its gc'ed
122     try {
123       LogManager.getLogManager().readConfiguration();
124     } catch (Exception e) {}
125     append("Testsuite: ");
126     append(suite.getName());
127     append(StringUtils.LINE_SEP);
128   }
129   
130   /**
131    * The whole testsuite ended.
132    * @param suite the test suite
133    */
134   public synchronized void endTestSuite(JUnitTest suite) {
135     append("Tests run: ");
136     append(suite.runCount());
137     append(", Failures: ");
138     append(suite.failureCount());
139     append(", Errors: ");
140     append(suite.errorCount());
141     append(", Time elapsed: ");
142     append(numberFormat.format(suite.getRunTime() / ONE_SECOND));
143     append(" sec");
144     append(StringUtils.LINE_SEP);
145     append(StringUtils.LINE_SEP);
146     
147     // append the err and output streams to the log
148     if (systemOutput != null && systemOutput.length() > 0) {
149       append("------------- Standard Output ---------------")
150       .append(StringUtils.LINE_SEP)
151       .append(systemOutput)
152       .append("------------- ---------------- ---------------")
153       .append(StringUtils.LINE_SEP);
154     }
155     
156     // HACK: junit gives us no way to do this in LuceneTestCase
157     try {
158       Class<?> clazz = Class.forName(suite.getName());
159       Ignore ignore = clazz.getAnnotation(Ignore.class);
160       if (ignore != null) {
161         if (systemError == null) systemError = "";
162         systemError += "NOTE: Ignoring test class '" + clazz.getSimpleName() + "': " 
163                     + ignore.value() + StringUtils.LINE_SEP;
164       }
165     } catch (ClassNotFoundException e) { /* no problem */ }
166     // END HACK
167     
168     if (systemError != null && systemError.length() > 0) {
169       append("------------- Standard Error -----------------")
170       .append(StringUtils.LINE_SEP)
171       .append(systemError)
172       .append("------------- ---------------- ---------------")
173       .append(StringUtils.LINE_SEP);
174     }
175     
176     if (out != null) {
177       try {
178         lock.obtain(5000);
179         try {
180           sb.writeTo(out);
181           out.flush();
182         } finally {
183           try {
184             lock.release();
185           } catch(LockReleaseFailedException e) {
186             // well lets pretend its released anyway
187           }
188         }
189       } catch (IOException e) {
190         throw new RuntimeException("unable to write results", e);
191       } finally {
192         if (out != System.out && out != System.err) {
193           FileUtils.close(out);
194         }
195       }
196     }
197   }
198   
199   /**
200    * A test started.
201    * @param test a test
202    */
203   public void startTest(Test test) {
204   }
205   
206   /**
207    * A test ended.
208    * @param test a test
209    */
210   public void endTest(Test test) {
211   }
212   
213   /**
214    * Interface TestListener for JUnit &lt;= 3.4.
215    *
216    * <p>A Test failed.
217    * @param test a test
218    * @param t    the exception thrown by the test
219    */
220   public void addFailure(Test test, Throwable t) {
221     formatError("\tFAILED", test, t);
222   }
223   
224   /**
225    * Interface TestListener for JUnit &gt; 3.4.
226    *
227    * <p>A Test failed.
228    * @param test a test
229    * @param t    the assertion failed by the test
230    */
231   public void addFailure(Test test, AssertionFailedError t) {
232     addFailure(test, (Throwable) t);
233   }
234   
235   /**
236    * A test caused an error.
237    * @param test  a test
238    * @param error the error thrown by the test
239    */
240   public void addError(Test test, Throwable error) {
241     formatError("\tCaused an ERROR", test, error);
242   }
243   
244   /**
245    * Format the test for printing..
246    * @param test a test
247    * @return the formatted testname
248    */
249   protected String formatTest(Test test) {
250     if (test == null) {
251       return "Null Test: ";
252     } else {
253       return "Testcase: " + test.toString() + ":";
254     }
255   }
256   
257   /**
258    * Format an error and print it.
259    * @param type the type of error
260    * @param test the test that failed
261    * @param error the exception that the test threw
262    */
263   protected synchronized void formatError(String type, Test test,
264       Throwable error) {
265     if (test != null) {
266       endTest(test);
267     }
268     
269     append(formatTest(test) + type);
270     append(StringUtils.LINE_SEP);
271     append(error.getMessage());
272     append(StringUtils.LINE_SEP);
273     String strace = JUnitTestRunner.getFilteredTrace(error);
274     append(strace);
275     append(StringUtils.LINE_SEP);
276     append(StringUtils.LINE_SEP);
277   }
278
279   public LuceneJUnitResultFormatter append(String s) {
280     if (s == null)
281       s = "(null)";
282     try {
283       sb.write(s.getBytes()); // intentionally use default charset, its a console.
284     } catch (IOException e) {
285       throw new RuntimeException(e);
286     }
287     return this;
288   }
289   
290   public LuceneJUnitResultFormatter append(long l) {
291     return append(Long.toString(l));
292   }
293 }
294