JTap.java
Go to the documentation of this file.
1 // ============================================================================
2 // Copyright (c) Patrick LeBoutillier
3 // Copyright (c) 2011 University of Pennsylvania
4 // All rights reserved.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // @sa http://testanything.org/wiki/index.php/Tap-functions
17 // ============================================================================
18 
19 /**
20  * @file JTap.java
21  * @brief Unit testing framework for Java based on the Test Anything Protocol.
22  *
23  * @author Patrick LeBoutillier <patl at cpan.org>
24  *
25  * @note This file is a copy of the JTap.java file which is part of the
26  * JTap project (http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/).
27  * The original implementation has been modified by Andreas Schuh as
28  * part of the BASIS project at SBIA.
29  *
30  * @ingroup BasisJavaUtilities
31  */
32 
33 import java.io.* ;
34 
35 
36 public class JTap {
37  final private String version = "1.0" ;
38 
39  private boolean plan_set = false ;
40  private boolean no_plan = false ;
41  private boolean skip_all = false ;
42  private boolean test_died = false ;
43  private int expected_tests = 0 ;
44  private int executed_tests = 0 ;
45  private int failed_tests = 0 ;
46  private boolean exit = true ;
47  private String todo = null ;
48 
49  private PrintStream out = null ;
50  private PrintStream err = null ;
51 
52 
53  public JTap(){
54  this(true) ;
55  }
56 
57 
58  public JTap(boolean really_exit){
59  out = System.out ;
60  err = System.err ;
61  exit = really_exit ;
62  }
63 
64 
65 
66 
67  synchronized public int plan_no_plan(){
68  if (plan_set){
69  die("You tried to plan twice!") ;
70  }
71 
72  plan_set = true ;
73  no_plan = true ;
74 
75  return 1 ;
76  }
77 
78 
79  synchronized public int plan_skip_all(String reason){
80  if (plan_set){
81  die("You tried to plan twice!") ;
82  }
83 
84  print_plan(0, "Skip " + reason) ;
85 
86  skip_all = true ;
87  plan_set = true ;
88 
89  exit(0) ;
90 
91  return 0 ;
92  }
93 
94 
95  synchronized public int plan_tests(int tests){
96  if (plan_set){
97  die("You tried to plan twice!") ;
98  }
99 
100  if (tests == 0){
101  die("You said to run 0 tests! You've got to run something.") ;
102  }
103 
104  print_plan(tests) ;
105  expected_tests = tests ;
106 
107  plan_set = true ;
108 
109  return tests ;
110  }
111 
112 
113  private void print_plan(int expected){
114  print_plan(expected, null) ;
115  }
116 
117 
118  synchronized private void print_plan(int expected_tests, String directive){
119  out.print("1.." + expected_tests) ;
120  if (directive != null){
121  out.print(" # " + directive) ;
122  }
123  out.print("\n") ;
124  out.flush() ;
125  }
126 
127 
128 
129 
130  public boolean pass(String name){
131  return ok(true, name) ;
132  }
133 
134 
135  public boolean fail(String name){
136  return ok(false, name) ;
137  }
138 
139 
140  public boolean ok(boolean result){
141  return ok(result, null) ;
142  }
143 
144 
145  /*
146  This is the workhorse method that actually
147  prints the tests result.
148  */
149  synchronized public boolean ok(boolean result, String name){
150  if (! plan_set){
151  die("You tried to run a test without a plan! Gotta have a plan.") ;
152  }
153 
154  executed_tests++ ;
155 
156  if (name != null) {
157  if (name.matches("[\\d\\s]+")){
158  diag(" You named your test '" + name
159  + "'. You shouldn't use numbers for your test names.") ;
160  diag(" Very confusing.") ;
161  }
162  }
163 
164  if (! result){
165  out.print("not ") ;
166  failed_tests++ ;
167  }
168  out.print("ok " + executed_tests) ;
169 
170  if (name != null) {
171  out.print(" - ") ;
172  out.print(name.replaceAll("#", "\\\\#")) ;
173  }
174 
175  if (todo != null){
176  out.print(" # TODO " + todo) ;
177  if (! result){
178  failed_tests-- ;
179  }
180  }
181 
182  out.print("\n") ;
183  out.flush() ;
184  if (! result){
185  Throwable t = new Throwable() ;
186  StackTraceElement stack[] = t.getStackTrace() ;
187  String file = null ;
188  String clas = null ;
189  String func = null ;
190  int line = 0 ;
191 
192  try {
193  for (int i = 0 ; i < stack.length ; i++){
194  Class c = Class.forName(stack[i].getClassName()) ;
195  if (! JTap.class.isAssignableFrom(c)){
196  // We are outside a JTap object, so this is probably the callpoint
197  file = stack[i].getFileName() ;
198  clas = c.getName() ;
199  func = stack[i].getMethodName() ;
200  line = stack[i].getLineNumber() ;
201  break ;
202  }
203  }
204  }
205  catch (Exception e){
206  e.printStackTrace() ;
207  }
208 
209  if (name != null){
210  diag(" Failed " + (todo == null ? "" : "(TODO) ") + "test '" + name + "'") ;
211  diag(" in " + file + ":" + func + "() at line " + line + ".") ;
212  }
213  else {
214  diag(" Failed " + (todo == null ? "" : "(TODO) ") + "test in " + file + ":" + func + "() at line " + line + ".") ;
215  }
216  }
217 
218  return result ;
219  }
220 
221 
222  private boolean equals(Object result, Object expected){
223  boolean r ;
224 
225  if ((result == null)&&(expected == null)){
226  r = true ;
227  }
228  else if ((result == null)||(expected == null)){
229  r = false ;
230  }
231  else {
232  r = result.equals(expected) ;
233  }
234 
235  return r ;
236  }
237 
238 
239  private boolean matches(Object result, String pattern){
240  boolean r ;
241 
242  if ((result == null)||(pattern == null)){
243  r = false ;
244  }
245  else {
246  r = result.toString().matches(pattern) ;
247  }
248 
249  return r ;
250  }
251 
252 
253  private void is_diag(Object result, Object expected){
254  diag(" got: '" + result + "'") ;
255  diag(" expected: '" + expected + "'") ;
256  }
257 
258 
259  public boolean is(Object result, Object expected){
260  return is(result, expected, null) ;
261  }
262 
263 
264  public boolean is(Object result, Object expected, String name){
265  boolean r = ok(equals(result, expected), name) ;
266  if (! r){
267  is_diag(result, expected) ;
268  }
269  return r ;
270  }
271 
272 
273  public boolean is(long result, long expected){
274  return is(new Long(result), new Long(expected)) ;
275  }
276 
277 
278  public boolean is(long result, long expected, String name){
279  return is(new Long(result), new Long(expected), name) ;
280  }
281 
282 
283  public boolean is(double result, double expected){
284  return is(new Double(result), new Double(expected)) ;
285  }
286 
287 
288  public boolean is(double result, double expected, String name){
289  return is(new Double(result), new Double(expected), name) ;
290  }
291 
292 
293  public boolean isnt(Object result, Object expected){
294  return isnt(result, expected, null) ;
295  }
296 
297 
298  public boolean isnt(Object result, Object expected, String name){
299  boolean r = ok(! equals(result, expected), name) ;
300  if (! r){
301  is_diag(result, expected) ;
302  }
303  return r ;
304  }
305 
306 
307  public boolean isnt(long result, long expected){
308  return isnt(new Long(result), new Long(expected)) ;
309  }
310 
311 
312  public boolean isnt(long result, long expected, String name){
313  return isnt(new Long(result), new Long(expected), name) ;
314  }
315 
316 
317  public boolean isnt(double result, double expected){
318  return isnt(new Double(result), new Double(expected)) ;
319  }
320 
321 
322  public boolean isnt(double result, double expected, String name){
323  return isnt(new Double(result), new Double(expected), name) ;
324  }
325 
326 
327  public boolean like(Object result, String pattern){
328  return like(result, pattern, null) ;
329  }
330 
331 
332  public boolean like(Object result, String pattern, String name){
333  boolean r = ok(matches(result, pattern), name) ;
334  if (! r){
335  diag(" " + result + " doesn't match '" + pattern + "'") ;
336  }
337  return r ;
338  }
339 
340 
341  public boolean unlike(Object result, String pattern){
342  return unlike(result, pattern, null) ;
343  }
344 
345 
346  public boolean unlike(Object result, String pattern, String name){
347  boolean r = ok(! matches(result, pattern), name) ;
348  if (! r){
349  diag(" " + result + " matches '" + pattern + "'") ;
350  }
351  return r ;
352  }
353 
354 
355  public boolean isa_ok(Object o, Class c){
356  return isa_ok(o, c, null) ;
357  }
358 
359 
360  public boolean isa_ok(Object o, Class c, String name){
361  boolean r = false ;
362  if ((o == null)||(c == null)){
363  r = false ;
364  }
365  else {
366  r = ok(c.isInstance(o), name) ;
367  }
368  if (! r){
369  diag(" Object isn't a '" + c.getName() + "' it's a '" + o.getClass().getName() + "'") ;
370  }
371 
372  return r ;
373  }
374 
375 
376 
377 
378  synchronized public void skip(String reason){
379  skip(reason, 1) ;
380  }
381 
382 
383  synchronized public void skip(String reason, int n){
384  for (int i = 0 ; i < n ; i++){
385  executed_tests++ ;
386  out.print("ok " + executed_tests + " # skip " + reason + "\n") ;
387  out.flush() ;
388  }
389  throw new JTapSkipException(reason) ;
390  }
391 
392 
393  synchronized public void todo_start(String reason){
394  if (reason.equals("")){
395  reason = null ;
396  }
397  todo = reason ;
398  }
399 
400 
401  synchronized public void todo_end(){
402  todo = null ;
403  }
404 
405 
406  synchronized public boolean diag(String msg){
407  if (msg != null){
408  String lines[] = msg.split("\n") ;
409  StringBuffer buf = new StringBuffer() ;
410  for (int i = 0 ; i < lines.length ; i++){
411  buf.append("# " + lines[i] + "\n") ;
412  }
413  out.print(buf) ;
414  out.flush() ;
415  }
416  return false ;
417  }
418 
419 
420 
421 
422  synchronized private void die(String reason){
423  err.println(reason) ;
424  test_died = true ;
425  exit(255) ;
426  }
427 
428 
429  synchronized public void BAIL_OUT(String reason){
430  out.println("Bail out! " + reason) ;
431  out.flush() ;
432  exit(255) ;
433  }
434 
435 
436  private int cleanup(){
437  int rc = 0 ;
438 
439  if (! plan_set){
440  diag("Looks like your test died before it could output anything.") ;
441  return rc ;
442  }
443 
444  if (test_died){
445  diag("Looks like your test died just after " + executed_tests + ".") ;
446  return rc ;
447  }
448 
449  if ((! skip_all)&&(no_plan)){
450  print_plan(executed_tests) ;
451  }
452 
453  if ((! no_plan)&&(expected_tests < executed_tests)) {
454  diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but ran "
455  + (executed_tests - expected_tests) + " extra.") ;
456  rc = -1 ;
457  }
458 
459  if ((! no_plan)&&(expected_tests > executed_tests)) {
460  diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but only ran "
461  + executed_tests + ".") ;
462  }
463 
464  if (failed_tests > 0){
465  diag("Looks like you failed " + failed_tests + " test" + (failed_tests > 1 ? "s" : "") + " of " + executed_tests + ".") ;
466  }
467 
468  return rc ;
469  }
470 
471 
472  synchronized public int exit_status(){
473  if ((no_plan)||(! plan_set)){
474  return failed_tests ;
475  }
476 
477  if (expected_tests < executed_tests){
478  return executed_tests - expected_tests ;
479  }
480 
481  return failed_tests + (expected_tests - executed_tests) ;
482  }
483 
484 
485  synchronized public void exit(){
486  exit(exit_status()) ;
487  }
488 
489 
490  synchronized private void exit(int rc){
491  int alt_rc = cleanup() ;
492  if (alt_rc != 0){
493  rc = alt_rc ;
494  }
495  if (exit){
496  System.exit(rc) ;
497  }
498  else {
499  throw new JTapExitException(rc) ;
500  }
501  }
502 }
503 
504 
505 
506 
507 class JTapException extends RuntimeException {
508  JTapException(String msg){
509  super(msg) ;
510  }
511 }
512 
513 
514 
515 
516 class JTapExitException extends JTapException {
517  JTapExitException(int rc){
518  super("exit " + rc) ;
519  }
520 }
521 
522 
523 
524 
525 class JTapSkipException extends JTapException {
526  JTapSkipException(String reason){
527  super("skip " + reason) ;
528  }
529 }
530 
531 
532 
synchronized void exit()
Definition: JTap.java:485
boolean is(Object result, Object expected, String name)
Definition: JTap.java:264
synchronized void todo_end()
Definition: JTap.java:401
Definition: JTap.java:36
JTap()
Definition: JTap.java:53
boolean isnt(double result, double expected, String name)
Definition: JTap.java:322
boolean isnt(Object result, Object expected, String name)
Definition: JTap.java:298
synchronized void skip(String reason, int n)
Definition: JTap.java:383
boolean like(Object result, String pattern, String name)
Definition: JTap.java:332
synchronized boolean ok(boolean result, String name)
Definition: JTap.java:149
JTap(boolean really_exit)
Definition: JTap.java:58
synchronized int plan_tests(int tests)
Definition: JTap.java:95
boolean is(double result, double expected)
Definition: JTap.java:283
boolean is(long result, long expected)
Definition: JTap.java:273
synchronized void BAIL_OUT(String reason)
Definition: JTap.java:429
boolean unlike(Object result, String pattern, String name)
Definition: JTap.java:346
synchronized int plan_no_plan()
Definition: JTap.java:67
synchronized boolean diag(String msg)
Definition: JTap.java:406
boolean is(long result, long expected, String name)
Definition: JTap.java:278
synchronized void todo_start(String reason)
Definition: JTap.java:393
boolean isa_ok(Object o, Class c, String name)
Definition: JTap.java:360
boolean is(Object result, Object expected)
Definition: JTap.java:259
boolean isa_ok(Object o, Class c)
Definition: JTap.java:355
boolean fail(String name)
Definition: JTap.java:135
synchronized int exit_status()
Definition: JTap.java:472
boolean pass(String name)
Definition: JTap.java:130
boolean isnt(long result, long expected, String name)
Definition: JTap.java:312
cmake msg
boolean isnt(Object result, Object expected)
Definition: JTap.java:293
synchronized int plan_skip_all(String reason)
Definition: JTap.java:79
boolean unlike(Object result, String pattern)
Definition: JTap.java:341
boolean ok(boolean result)
Definition: JTap.java:140
boolean like(Object result, String pattern)
Definition: JTap.java:327
boolean isnt(long result, long expected)
Definition: JTap.java:307
boolean is(double result, double expected, String name)
Definition: JTap.java:288
synchronized void skip(String reason)
Definition: JTap.java:378
boolean isnt(double result, double expected)
Definition: JTap.java:317