1 package be
.nikiroo
.utils
.test
;
3 import java
.io
.PrintWriter
;
4 import java
.io
.StringWriter
;
5 import java
.util
.ArrayList
;
8 import be
.nikiroo
.utils
.test
.TestCase
.AssertException
;
11 * A {@link TestLauncher} starts a series of {@link TestCase}s and displays the
16 public class TestLauncher
{
18 * {@link Exception} happening during the setup process.
22 private class SetupException
extends Exception
{
23 private static final long serialVersionUID
= 1L;
25 public SetupException(Exception e
) {
31 * {@link Exception} happening during the tear-down process.
35 private class TearDownException
extends Exception
{
36 private static final long serialVersionUID
= 1L;
38 public TearDownException(Exception e
) {
43 private List
<TestLauncher
> series
;
44 private List
<TestCase
> tests
;
46 private String okString
;
47 private String koString
;
51 protected int executed
;
54 private int currentSeries
= 0;
57 * Create a new {@link TestLauncher} with default parameters.
62 * the arguments to configure the number of columns and the ok/ko
65 public TestLauncher(String name
, String
[] args
) {
69 if (args
!= null && args
.length
>= 1) {
71 cols
= Integer
.parseInt(args
[0]);
72 } catch (NumberFormatException e
) {
73 System
.err
.println("Test configuration: given number "
74 + "of columns is not parseable: " + args
[0]);
80 String okString
= "[ ok ]";
81 String koString
= "[ !! ]";
82 if (args
!= null && args
.length
>= 3) {
87 setOkString(okString
);
88 setKoString(koString
);
90 series
= new ArrayList
<TestLauncher
>();
91 tests
= new ArrayList
<TestCase
>();
96 * Called before actually starting the tests themselves.
101 protected void start() throws Exception
{
105 * Called when the tests are passed (or failed to do so).
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 (Exception e
) {
195 throw new SetupException(e
);
200 } catch (Exception e
) {
201 throw new TearDownException(e
);
203 } catch (Exception 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}
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
, Exception error
) {
307 System
.out
.println(" " + koString
);
308 String lines
= error
.getMessage() + "";
309 if (!(error
instanceof AssertException
)) {
310 StringWriter sw
= new StringWriter();
311 PrintWriter pw
= new PrintWriter(sw
);
312 error
.printStackTrace(pw
);
313 lines
= sw
.toString();
315 for (String line
: lines
.split("\n")) {
316 System
.out
.println(prefix(depth
, false) + "\t\t" + line
);
319 System
.out
.println(" " + okString
);
324 * Print the total result for this test suite.
327 * the level at which is the launcher (0 = main launcher)
329 * the number of tests actually ran
331 * the number of errors encountered
333 * the total number of tests in the suite
335 private void print(int depth
, int executed
, int errors
, int total
) {
336 int ok
= executed
- errors
;
337 int pc
= (int) ((100.0 * ok
) / executed
);
338 if (pc
== 0 && ok
> 0) {
341 int pcTotal
= (int) ((100.0 * ok
) / total
);
342 if (pcTotal
== 0 && ok
> 0) {
346 String resume
= "Tests passed: " + ok
+ "/" + executed
+ " (" + pc
347 + "%) on a total of " + total
+ " (" + pcTotal
+ "% total)";
349 System
.out
.println(resume
);
351 String arrow
= "┗▶ ";
352 System
.out
.println(prefix(depth
, currentSeries
== 0) + arrow
354 System
.out
.println(prefix(depth
, currentSeries
== 0));
358 private int last
= -1;
361 * Return the prefix to print before the current line.
366 * this line is the first of its tabulation level
370 private String
prefix(int depth
, boolean first
) {
371 String space
= tabs(depth
- 1);
376 if (depth
!= last
&& first
) {
377 line
= "╻"; // first line
379 line
= "┃"; // continuation
383 space
+= line
+ tabs(1);
391 * Return the given number of space-converted tabs in a {@link String}.
394 * the number of tabs to return
398 private String
tabs(int depth
) {
399 StringBuilder builder
= new StringBuilder();
400 for (int i
= 0; i
< depth
; i
++) {
403 return builder
.toString();