00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 import java.io.* ;
00034
00035
00036 public class JTap {
00037 final private String version = "1.0" ;
00038
00039 private boolean plan_set = false ;
00040 private boolean no_plan = false ;
00041 private boolean skip_all = false ;
00042 private boolean test_died = false ;
00043 private int expected_tests = 0 ;
00044 private int executed_tests = 0 ;
00045 private int failed_tests = 0 ;
00046 private boolean exit = true ;
00047 private String todo = null ;
00048
00049 private PrintStream out = null ;
00050 private PrintStream err = null ;
00051
00052
00053 public JTap(){
00054 this(true) ;
00055 }
00056
00057
00058 public JTap(boolean really_exit){
00059 out = System.out ;
00060 err = System.err ;
00061 exit = really_exit ;
00062 }
00063
00064
00065
00066
00067 synchronized public int plan_no_plan(){
00068 if (plan_set){
00069 die("You tried to plan twice!") ;
00070 }
00071
00072 plan_set = true ;
00073 no_plan = true ;
00074
00075 return 1 ;
00076 }
00077
00078
00079 synchronized public int plan_skip_all(String reason){
00080 if (plan_set){
00081 die("You tried to plan twice!") ;
00082 }
00083
00084 print_plan(0, "Skip " + reason) ;
00085
00086 skip_all = true ;
00087 plan_set = true ;
00088
00089 exit(0) ;
00090
00091 return 0 ;
00092 }
00093
00094
00095 synchronized public int plan_tests(int tests){
00096 if (plan_set){
00097 die("You tried to plan twice!") ;
00098 }
00099
00100 if (tests == 0){
00101 die("You said to run 0 tests! You've got to run something.") ;
00102 }
00103
00104 print_plan(tests) ;
00105 expected_tests = tests ;
00106
00107 plan_set = true ;
00108
00109 return tests ;
00110 }
00111
00112
00113 private void print_plan(int expected){
00114 print_plan(expected, null) ;
00115 }
00116
00117
00118 synchronized private void print_plan(int expected_tests, String directive){
00119 out.print("1.." + expected_tests) ;
00120 if (directive != null){
00121 out.print(" # " + directive) ;
00122 }
00123 out.print("\n") ;
00124 out.flush() ;
00125 }
00126
00127
00128
00129
00130 public boolean pass(String name){
00131 return ok(true, name) ;
00132 }
00133
00134
00135 public boolean fail(String name){
00136 return ok(false, name) ;
00137 }
00138
00139
00140 public boolean ok(boolean result){
00141 return ok(result, null) ;
00142 }
00143
00144
00145
00146
00147
00148
00149 synchronized public boolean ok(boolean result, String name){
00150 if (! plan_set){
00151 die("You tried to run a test without a plan! Gotta have a plan.") ;
00152 }
00153
00154 executed_tests++ ;
00155
00156 if (name != null) {
00157 if (name.matches("[\\d\\s]+")){
00158 diag(" You named your test '" + name
00159 + "'. You shouldn't use numbers for your test names.") ;
00160 diag(" Very confusing.") ;
00161 }
00162 }
00163
00164 if (! result){
00165 out.print("not ") ;
00166 failed_tests++ ;
00167 }
00168 out.print("ok " + executed_tests) ;
00169
00170 if (name != null) {
00171 out.print(" - ") ;
00172 out.print(name.replaceAll("#", "\\\\#")) ;
00173 }
00174
00175 if (todo != null){
00176 out.print(" # TODO " + todo) ;
00177 if (! result){
00178 failed_tests-- ;
00179 }
00180 }
00181
00182 out.print("\n") ;
00183 out.flush() ;
00184 if (! result){
00185 Throwable t = new Throwable() ;
00186 StackTraceElement stack[] = t.getStackTrace() ;
00187 String file = null ;
00188 String clas = null ;
00189 String func = null ;
00190 int line = 0 ;
00191
00192 try {
00193 for (int i = 0 ; i < stack.length ; i++){
00194 Class c = Class.forName(stack[i].getClassName()) ;
00195 if (! JTap.class.isAssignableFrom(c)){
00196
00197 file = stack[i].getFileName() ;
00198 clas = c.getName() ;
00199 func = stack[i].getMethodName() ;
00200 line = stack[i].getLineNumber() ;
00201 break ;
00202 }
00203 }
00204 }
00205 catch (Exception e){
00206 e.printStackTrace() ;
00207 }
00208
00209 if (name != null){
00210 diag(" Failed " + (todo == null ? "" : "(TODO) ") + "test '" + name + "'") ;
00211 diag(" in " + file + ":" + func + "() at line " + line + ".") ;
00212 }
00213 else {
00214 diag(" Failed " + (todo == null ? "" : "(TODO) ") + "test in " + file + ":" + func + "() at line " + line + ".") ;
00215 }
00216 }
00217
00218 return result ;
00219 }
00220
00221
00222 private boolean equals(Object result, Object expected){
00223 boolean r ;
00224
00225 if ((result == null)&&(expected == null)){
00226 r = true ;
00227 }
00228 else if ((result == null)||(expected == null)){
00229 r = false ;
00230 }
00231 else {
00232 r = result.equals(expected) ;
00233 }
00234
00235 return r ;
00236 }
00237
00238
00239 private boolean matches(Object result, String pattern){
00240 boolean r ;
00241
00242 if ((result == null)||(pattern == null)){
00243 r = false ;
00244 }
00245 else {
00246 r = result.toString().matches(pattern) ;
00247 }
00248
00249 return r ;
00250 }
00251
00252
00253 private void is_diag(Object result, Object expected){
00254 diag(" got: '" + result + "'") ;
00255 diag(" expected: '" + expected + "'") ;
00256 }
00257
00258
00259 public boolean is(Object result, Object expected){
00260 return is(result, expected, null) ;
00261 }
00262
00263
00264 public boolean is(Object result, Object expected, String name){
00265 boolean r = ok(equals(result, expected), name) ;
00266 if (! r){
00267 is_diag(result, expected) ;
00268 }
00269 return r ;
00270 }
00271
00272
00273 public boolean is(long result, long expected){
00274 return is(new Long(result), new Long(expected)) ;
00275 }
00276
00277
00278 public boolean is(long result, long expected, String name){
00279 return is(new Long(result), new Long(expected), name) ;
00280 }
00281
00282
00283 public boolean is(double result, double expected){
00284 return is(new Double(result), new Double(expected)) ;
00285 }
00286
00287
00288 public boolean is(double result, double expected, String name){
00289 return is(new Double(result), new Double(expected), name) ;
00290 }
00291
00292
00293 public boolean isnt(Object result, Object expected){
00294 return isnt(result, expected, null) ;
00295 }
00296
00297
00298 public boolean isnt(Object result, Object expected, String name){
00299 boolean r = ok(! equals(result, expected), name) ;
00300 if (! r){
00301 is_diag(result, expected) ;
00302 }
00303 return r ;
00304 }
00305
00306
00307 public boolean isnt(long result, long expected){
00308 return isnt(new Long(result), new Long(expected)) ;
00309 }
00310
00311
00312 public boolean isnt(long result, long expected, String name){
00313 return isnt(new Long(result), new Long(expected), name) ;
00314 }
00315
00316
00317 public boolean isnt(double result, double expected){
00318 return isnt(new Double(result), new Double(expected)) ;
00319 }
00320
00321
00322 public boolean isnt(double result, double expected, String name){
00323 return isnt(new Double(result), new Double(expected), name) ;
00324 }
00325
00326
00327 public boolean like(Object result, String pattern){
00328 return like(result, pattern, null) ;
00329 }
00330
00331
00332 public boolean like(Object result, String pattern, String name){
00333 boolean r = ok(matches(result, pattern), name) ;
00334 if (! r){
00335 diag(" " + result + " doesn't match '" + pattern + "'") ;
00336 }
00337 return r ;
00338 }
00339
00340
00341 public boolean unlike(Object result, String pattern){
00342 return unlike(result, pattern, null) ;
00343 }
00344
00345
00346 public boolean unlike(Object result, String pattern, String name){
00347 boolean r = ok(! matches(result, pattern), name) ;
00348 if (! r){
00349 diag(" " + result + " matches '" + pattern + "'") ;
00350 }
00351 return r ;
00352 }
00353
00354
00355 public boolean isa_ok(Object o, Class c){
00356 return isa_ok(o, c, null) ;
00357 }
00358
00359
00360 public boolean isa_ok(Object o, Class c, String name){
00361 boolean r = false ;
00362 if ((o == null)||(c == null)){
00363 r = false ;
00364 }
00365 else {
00366 r = ok(c.isInstance(o), name) ;
00367 }
00368 if (! r){
00369 diag(" Object isn't a '" + c.getName() + "' it's a '" + o.getClass().getName() + "'") ;
00370 }
00371
00372 return r ;
00373 }
00374
00375
00376
00377
00378 synchronized public void skip(String reason){
00379 skip(reason, 1) ;
00380 }
00381
00382
00383 synchronized public void skip(String reason, int n){
00384 for (int i = 0 ; i < n ; i++){
00385 executed_tests++ ;
00386 out.print("ok " + executed_tests + " # skip " + reason + "\n") ;
00387 out.flush() ;
00388 }
00389 throw new JTapSkipException(reason) ;
00390 }
00391
00392
00393 synchronized public void todo_start(String reason){
00394 if (reason.equals("")){
00395 reason = null ;
00396 }
00397 todo = reason ;
00398 }
00399
00400
00401 synchronized public void todo_end(){
00402 todo = null ;
00403 }
00404
00405
00406 synchronized public boolean diag(String msg){
00407 if (msg != null){
00408 String lines[] = msg.split("\n") ;
00409 StringBuffer buf = new StringBuffer() ;
00410 for (int i = 0 ; i < lines.length ; i++){
00411 buf.append("# " + lines[i] + "\n") ;
00412 }
00413 out.print(buf) ;
00414 out.flush() ;
00415 }
00416 return false ;
00417 }
00418
00419
00420
00421
00422 synchronized private void die(String reason){
00423 err.println(reason) ;
00424 test_died = true ;
00425 exit(255) ;
00426 }
00427
00428
00429 synchronized public void BAIL_OUT(String reason){
00430 out.println("Bail out! " + reason) ;
00431 out.flush() ;
00432 exit(255) ;
00433 }
00434
00435
00436 private int cleanup(){
00437 int rc = 0 ;
00438
00439 if (! plan_set){
00440 diag("Looks like your test died before it could output anything.") ;
00441 return rc ;
00442 }
00443
00444 if (test_died){
00445 diag("Looks like your test died just after " + executed_tests + ".") ;
00446 return rc ;
00447 }
00448
00449 if ((! skip_all)&&(no_plan)){
00450 print_plan(executed_tests) ;
00451 }
00452
00453 if ((! no_plan)&&(expected_tests < executed_tests)) {
00454 diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but ran "
00455 + (executed_tests - expected_tests) + " extra.") ;
00456 rc = -1 ;
00457 }
00458
00459 if ((! no_plan)&&(expected_tests > executed_tests)) {
00460 diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but only ran "
00461 + executed_tests + ".") ;
00462 }
00463
00464 if (failed_tests > 0){
00465 diag("Looks like you failed " + failed_tests + " test" + (failed_tests > 1 ? "s" : "") + " of " + executed_tests + ".") ;
00466 }
00467
00468 return rc ;
00469 }
00470
00471
00472 synchronized public int exit_status(){
00473 if ((no_plan)||(! plan_set)){
00474 return failed_tests ;
00475 }
00476
00477 if (expected_tests < executed_tests){
00478 return executed_tests - expected_tests ;
00479 }
00480
00481 return failed_tests + (expected_tests - executed_tests) ;
00482 }
00483
00484
00485 synchronized public void exit(){
00486 exit(exit_status()) ;
00487 }
00488
00489
00490 synchronized private void exit(int rc){
00491 int alt_rc = cleanup() ;
00492 if (alt_rc != 0){
00493 rc = alt_rc ;
00494 }
00495 if (exit){
00496 System.exit(rc) ;
00497 }
00498 else {
00499 throw new JTapExitException(rc) ;
00500 }
00501 }
00502 }
00503
00504
00505
00506
00507 class JTapException extends RuntimeException {
00508 JTapException(String msg){
00509 super(msg) ;
00510 }
00511 }
00512
00513
00514
00515
00516 class JTapExitException extends JTapException {
00517 JTapExitException(int rc){
00518 super("exit " + rc) ;
00519 }
00520 }
00521
00522
00523
00524
00525 class JTapSkipException extends JTapException {
00526 JTapSkipException(String reason){
00527 super("skip " + reason) ;
00528 }
00529 }
00530
00531
00532