1 package be
.nikiroo
.utils
.test
;
3 import java
.io
.PrintWriter
;
4 import java
.io
.StringWriter
;
5 import java
.util
.ArrayList
;
9 * A {@link TestLauncher} starts a series of {@link TestCase}s and displays the
14 public class TestLauncher
{
16 * {@link Exception} happening during the setup process.
20 private class SetupException
extends Exception
{
21 private static final long serialVersionUID
= 1L;
23 public SetupException(Throwable e
) {
29 * {@link Exception} happening during the tear-down process.
33 private class TearDownException
extends Exception
{
34 private static final long serialVersionUID
= 1L;
36 public TearDownException(Throwable e
) {
41 private List
<TestLauncher
> series
;
42 private List
<TestCase
> tests
;
44 private String okString
;
45 private String koString
;
49 protected int executed
;
52 private int currentSeries
= 0;
55 * Create a new {@link TestLauncher} with default parameters.
60 * the arguments to configure the number of columns and the ok/ko
63 public TestLauncher(String name
, String
[] args
) {
67 if (args
!= null && args
.length
>= 1) {
69 cols
= Integer
.parseInt(args
[0]);
70 } catch (NumberFormatException e
) {
71 System
.err
.println("Test configuration: given number "
72 + "of columns is not parseable: " + args
[0]);
78 String okString
= "[ ok ]";
79 String koString
= "[ !! ]";
80 if (args
!= null && args
.length
>= 3) {
85 setOkString(okString
);
86 setKoString(koString
);
88 series
= new ArrayList
<TestLauncher
>();
89 tests
= new ArrayList
<TestCase
>();
94 * Called before actually starting the tests themselves.
99 @SuppressWarnings("unused")
100 protected void start() throws Exception
{
104 * Called when the tests are passed (or failed to do so).
109 @SuppressWarnings("unused")
110 protected void stop() throws Exception
{
113 protected void addTest(TestCase test
) {
117 protected void addSeries(TestLauncher series
) {
118 this.series
.add(series
);
122 * Launch the series of {@link TestCase}s and the {@link TestCase}s.
124 * @return the number of errors
126 public int launch() {
131 * Launch the series of {@link TestCase}s and the {@link TestCase}s.
134 * the level at which is the launcher (0 = main launcher)
136 * @return the number of errors
138 public int launch(int depth
) {
141 total
= tests
.size();
148 errors
+= launchTests(depth
);
149 if (tests
.size() > 0 && depth
== 0) {
150 System
.out
.println("");
154 for (TestLauncher serie
: series
) {
155 errors
+= serie
.launch(depth
+ 1);
156 executed
+= serie
.executed
;
157 total
+= serie
.total
;
160 } catch (Exception e
) {
161 print(depth
, "__start");
166 } catch (Exception e
) {
167 print(depth
, "__stop");
172 print(depth
, executed
, errors
, total
);
178 * Launch the {@link TestCase}s.
181 * the level at which is the launcher (0 = main launcher)
183 * @return the number of errors
185 protected int launchTests(int depth
) {
187 for (TestCase test
: tests
) {
188 print(depth
, test
.getName());
194 } catch (Throwable e
) {
195 throw new SetupException(e
);
200 } catch (Throwable e
) {
201 throw new TearDownException(e
);
203 } catch (Throwable e
) {
215 if (ex
!= null && !cont
) {
224 * Specify a custom number of columns to use for the display of messages.
227 * the number of columns
229 public void setColumns(int columns
) {
230 this.columns
= columns
;
234 * Continue to run the tests when an error is detected.
239 public void setContinueAfterFail(boolean cont
) {
244 * Set a custom "[ ok ]" {@link String} when a test passed.
247 * the {@link String} to display at the end of a success
249 public void setOkString(String okString
) {
250 this.okString
= okString
;
254 * Set a custom "[ !! ]" {@link String} when a test failed.
257 * the {@link String} to display at the end of a failure
259 public void setKoString(String koString
) {
260 this.koString
= koString
;
264 * Print the test suite header.
267 * the level at which is the launcher (0 = main launcher)
269 protected void print(int depth
) {
271 System
.out
.println("[ Test suite: " + name
+ " ]");
272 System
.out
.println("");
274 System
.out
.println(prefix(depth
, false) + name
+ ":");
279 * Print the name of the {@link TestCase} we will start immediately after.
282 * the level at which is the launcher (0 = main launcher)
284 * the {@link TestCase} name
286 protected void print(int depth
, String name
) {
287 name
= prefix(depth
, false)
288 + (name
== null ?
"" : name
).replace("\t", " ");
290 while (name
.length() < columns
- 11) {
294 System
.out
.print(name
);
298 * Print the result of the {@link TestCase} we just ran.
301 * the level at which is the launcher (0 = main launcher)
303 * the {@link Exception} it ran into if any
305 private void print(int depth
, Throwable error
) {
307 System
.out
.println(" " + koString
);
308 StringWriter sw
= new StringWriter();
309 PrintWriter pw
= new PrintWriter(sw
);
310 error
.printStackTrace(pw
);
311 String lines
= sw
.toString();
312 for (String line
: lines
.split("\n")) {
313 System
.out
.println(prefix(depth
, false) + "\t\t" + line
);
316 System
.out
.println(" " + okString
);
321 * Print the total result for this test suite.
324 * the level at which is the launcher (0 = main launcher)
326 * the number of tests actually ran
328 * the number of errors encountered
330 * the total number of tests in the suite
332 private void print(int depth
, int executed
, int errors
, int total
) {
333 int ok
= executed
- errors
;
334 int pc
= (int) ((100.0 * ok
) / executed
);
335 if (pc
== 0 && ok
> 0) {
338 int pcTotal
= (int) ((100.0 * ok
) / total
);
339 if (pcTotal
== 0 && ok
> 0) {
343 String resume
= "Tests passed: " + ok
+ "/" + executed
+ " (" + pc
344 + "%) on a total of " + total
+ " (" + pcTotal
+ "% total)";
346 System
.out
.println(resume
);
348 String arrow
= "┗▶ ";
349 System
.out
.println(prefix(depth
, currentSeries
== 0) + arrow
351 System
.out
.println(prefix(depth
, currentSeries
== 0));
355 private int last
= -1;
358 * Return the prefix to print before the current line.
363 * this line is the first of its tabulation level
367 private String
prefix(int depth
, boolean first
) {
368 String space
= tabs(depth
- 1);
373 if (depth
!= last
&& first
) {
374 line
= "╻"; // first line
376 line
= "┃"; // continuation
380 space
+= line
+ tabs(1);
388 * Return the given number of space-converted tabs in a {@link String}.
391 * the number of tabs to return
395 private String
tabs(int depth
) {
396 StringBuilder builder
= new StringBuilder();
397 for (int i
= 0; i
< depth
; i
++) {
400 return builder
.toString();