1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 27 * @summary tests error and diagnostics positions 28 * @author Jan Lahoda 29 * @modules jdk.compiler/com.sun.tools.javac.api 30 * jdk.compiler/com.sun.tools.javac.main 31 * jdk.compiler/com.sun.tools.javac.tree 32 */ 33 34 import com.sun.source.tree.BinaryTree; 35 import com.sun.source.tree.BlockTree; 36 import com.sun.source.tree.ClassTree; 37 import com.sun.source.tree.CompilationUnitTree; 38 import com.sun.source.tree.ErroneousTree; 39 import com.sun.source.tree.ExpressionStatementTree; 40 import com.sun.source.tree.ExpressionTree; 41 import com.sun.source.tree.IfTree; 42 import com.sun.source.tree.LambdaExpressionTree; 43 import com.sun.source.tree.MethodInvocationTree; 44 import com.sun.source.tree.MethodTree; 45 import com.sun.source.tree.ModifiersTree; 46 import com.sun.source.tree.PrimitiveTypeTree; 47 import com.sun.source.tree.StatementTree; 48 import com.sun.source.tree.Tree; 49 import com.sun.source.tree.Tree.Kind; 50 import com.sun.source.tree.VariableTree; 51 import com.sun.source.tree.WhileLoopTree; 52 import com.sun.source.util.JavacTask; 53 import com.sun.source.util.SourcePositions; 54 import com.sun.source.util.TreePath; 55 import com.sun.source.util.TreePathScanner; 56 import com.sun.source.util.TreeScanner; 57 import com.sun.source.util.Trees; 58 import com.sun.tools.javac.api.JavacTaskImpl; 59 import com.sun.tools.javac.main.Main; 60 import com.sun.tools.javac.main.Main.Result; 61 import com.sun.tools.javac.tree.JCTree; 62 import java.io.IOException; 63 import java.io.StringWriter; 64 import java.lang.annotation.ElementType; 65 import java.lang.annotation.Retention; 66 import java.lang.annotation.RetentionPolicy; 67 import java.lang.annotation.Target; 68 import java.lang.reflect.Method; 69 import java.net.URI; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.LinkedList; 73 import java.util.List; 74 import java.util.regex.Pattern; 75 import javax.lang.model.type.TypeKind; 76 import javax.tools.Diagnostic; 77 import javax.tools.DiagnosticCollector; 78 import javax.tools.DiagnosticListener; 79 import javax.tools.JavaCompiler; 80 import javax.tools.JavaFileManager; 81 import javax.tools.JavaFileObject; 82 import javax.tools.SimpleJavaFileObject; 83 import javax.tools.ToolProvider; 84 85 import com.sun.source.tree.CaseTree; 86 import com.sun.source.util.TreePathScanner; 87 88 public class JavacParserTest extends TestCase { 89 static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 90 static final JavaFileManager fm = tool.getStandardFileManager(null, null, null); 91 92 private JavacParserTest(){} 93 94 public static void main(String... args) throws Exception { 95 try { 96 new JavacParserTest().run(args); 97 } finally { 98 fm.close(); 99 } 100 } 101 102 class MyFileObject extends SimpleJavaFileObject { 103 104 private String text; 105 106 public MyFileObject(String text) { 107 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 108 this.text = text; 109 } 110 111 @Override 112 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 113 return text; 114 } 115 } 116 /* 117 * converts Windows to Unix style LFs for comparing strings 118 */ 119 String normalize(String in) { 120 return in.replace(System.getProperty("line.separator"), "\n"); 121 } 122 123 CompilationUnitTree getCompilationUnitTree(String code) throws IOException { 124 125 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 126 null, Arrays.asList(new MyFileObject(code))); 127 CompilationUnitTree cut = ct.parse().iterator().next(); 128 return cut; 129 } 130 131 List<String> getErroneousTreeValues(ErroneousTree node) { 132 133 List<String> values = new ArrayList<>(); 134 if (node.getErrorTrees() != null) { 135 for (Tree t : node.getErrorTrees()) { 136 values.add(t.toString()); 137 } 138 } else { 139 throw new RuntimeException("ERROR: No Erroneous tree " 140 + "has been created."); 141 } 142 return values; 143 } 144 145 @Test 146 void testPositionForSuperConstructorCalls() throws IOException { 147 assert tool != null; 148 149 String code = "package test; public class Test {public Test() {super();}}"; 150 151 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 152 null, Arrays.asList(new MyFileObject(code))); 153 CompilationUnitTree cut = ct.parse().iterator().next(); 154 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 155 156 MethodTree method = 157 (MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0); 158 ExpressionStatementTree es = 159 (ExpressionStatementTree) method.getBody().getStatements().get(0); 160 161 final int esStartPos = code.indexOf(es.toString()); 162 final int esEndPos = esStartPos + es.toString().length(); 163 assertEquals("testPositionForSuperConstructorCalls", 164 esStartPos, pos.getStartPosition(cut, es)); 165 assertEquals("testPositionForSuperConstructorCalls", 166 esEndPos, pos.getEndPosition(cut, es)); 167 168 MethodInvocationTree mit = (MethodInvocationTree) es.getExpression(); 169 170 final int mitStartPos = code.indexOf(mit.toString()); 171 final int mitEndPos = mitStartPos + mit.toString().length(); 172 assertEquals("testPositionForSuperConstructorCalls", 173 mitStartPos, pos.getStartPosition(cut, mit)); 174 assertEquals("testPositionForSuperConstructorCalls", 175 mitEndPos, pos.getEndPosition(cut, mit)); 176 177 final int methodStartPos = mitStartPos; 178 final int methodEndPos = methodStartPos + mit.getMethodSelect().toString().length(); 179 assertEquals("testPositionForSuperConstructorCalls", 180 methodStartPos, pos.getStartPosition(cut, mit.getMethodSelect())); 181 assertEquals("testPositionForSuperConstructorCalls", 182 methodEndPos, pos.getEndPosition(cut, mit.getMethodSelect())); 183 } 184 185 @Test 186 void testPositionForEnumModifiers() throws IOException { 187 final String theString = "public"; 188 String code = "package test; " + theString + " enum Test {A;}"; 189 190 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 191 null, Arrays.asList(new MyFileObject(code))); 192 CompilationUnitTree cut = ct.parse().iterator().next(); 193 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 194 195 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 196 ModifiersTree mt = clazz.getModifiers(); 197 int spos = code.indexOf(theString); 198 int epos = spos + theString.length(); 199 assertEquals("testPositionForEnumModifiers", 200 spos, pos.getStartPosition(cut, mt)); 201 assertEquals("testPositionForEnumModifiers", 202 epos, pos.getEndPosition(cut, mt)); 203 } 204 205 @Test 206 void testNewClassWithEnclosing() throws IOException { 207 208 final String theString = "Test.this.new d()"; 209 String code = "package test; class Test { " + 210 "class d {} private void method() { " + 211 "Object o = " + theString + "; } }"; 212 213 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 214 null, Arrays.asList(new MyFileObject(code))); 215 CompilationUnitTree cut = ct.parse().iterator().next(); 216 SourcePositions pos = Trees.instance(ct).getSourcePositions(); 217 218 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 219 ExpressionTree est = 220 ((VariableTree) ((MethodTree) clazz.getMembers().get(1)).getBody().getStatements().get(0)).getInitializer(); 221 222 final int spos = code.indexOf(theString); 223 final int epos = spos + theString.length(); 224 assertEquals("testNewClassWithEnclosing", 225 spos, pos.getStartPosition(cut, est)); 226 assertEquals("testNewClassWithEnclosing", 227 epos, pos.getEndPosition(cut, est)); 228 } 229 230 @Test 231 void testPreferredPositionForBinaryOp() throws IOException { 232 233 String code = "package test; public class Test {" 234 + "private void test() {" 235 + "Object o = null; boolean b = o != null && o instanceof String;" 236 + "} private Test() {}}"; 237 238 CompilationUnitTree cut = getCompilationUnitTree(code); 239 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 240 MethodTree method = (MethodTree) clazz.getMembers().get(0); 241 VariableTree condSt = (VariableTree) method.getBody().getStatements().get(1); 242 BinaryTree cond = (BinaryTree) condSt.getInitializer(); 243 244 JCTree condJC = (JCTree) cond; 245 int condStartPos = code.indexOf("&&"); 246 assertEquals("testPreferredPositionForBinaryOp", 247 condStartPos, condJC.pos); 248 } 249 250 @Test 251 void testErrorRecoveryForEnhancedForLoop142381() throws IOException { 252 253 String code = "package test; class Test { " + 254 "private void method() { " + 255 "java.util.Set<String> s = null; for (a : s) {} } }"; 256 257 final List<Diagnostic<? extends JavaFileObject>> errors = 258 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 259 260 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 261 new DiagnosticListener<JavaFileObject>() { 262 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 263 errors.add(diagnostic); 264 } 265 }, null, null, Arrays.asList(new MyFileObject(code))); 266 267 CompilationUnitTree cut = ct.parse().iterator().next(); 268 269 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 270 StatementTree forStatement = 271 ((MethodTree) clazz.getMembers().get(0)).getBody().getStatements().get(1); 272 273 assertEquals("testErrorRecoveryForEnhancedForLoop142381", 274 Kind.ENHANCED_FOR_LOOP, forStatement.getKind()); 275 assertFalse("testErrorRecoveryForEnhancedForLoop142381", errors.isEmpty()); 276 } 277 278 @Test 279 void testPositionAnnotationNoPackage187551() throws IOException { 280 281 String code = "\n@interface Test {}"; 282 283 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 284 null, Arrays.asList(new MyFileObject(code))); 285 286 CompilationUnitTree cut = ct.parse().iterator().next(); 287 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 288 Trees t = Trees.instance(ct); 289 290 assertEquals("testPositionAnnotationNoPackage187551", 291 1, t.getSourcePositions().getStartPosition(cut, clazz)); 292 } 293 294 @Test 295 void testPositionMissingStatement() throws IOException { 296 String code = "class C { void t() { if (true) } }"; 297 DiagnosticCollector<JavaFileObject> dc = new DiagnosticCollector<>(); 298 299 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, dc, null, 300 null, Arrays.asList(new MyFileObject(code))); 301 302 CompilationUnitTree cut = ct.parse().iterator().next(); 303 Trees trees = Trees.instance(ct); 304 SourcePositions positions = trees.getSourcePositions(); 305 306 new TreeScanner<Void, Void>() { 307 @Override 308 public Void visitIf(IfTree it, Void v) { 309 StatementTree st = it.getThenStatement(); 310 int startpos = (int) positions.getStartPosition(cut, st); 311 int endpos = (int) positions.getEndPosition(cut, st); 312 assertEquals("testPositionMissingStatement.execpos", startpos, endpos); 313 assertEquals("testPositionMissingStatement.execkind", 314 Kind.EXPRESSION_STATEMENT, 315 st.getKind()); 316 Tree err = ((ExpressionStatementTree) st).getExpression(); 317 startpos = (int) positions.getStartPosition(cut, err); 318 endpos = (int) positions.getEndPosition(cut, err); 319 assertEquals("testPositionMissingStatement.errpos", startpos, endpos); 320 assertEquals("testPositionMissingStatement.errkind", 321 Kind.ERRONEOUS, 322 err.getKind()); 323 return super.visitIf(it, v); 324 } 325 }.scan(cut, null); 326 327 assertEquals("testPositionMissingStatement.diags", 1, dc.getDiagnostics().size()); 328 Diagnostic<? extends JavaFileObject> d = dc.getDiagnostics().get(0); 329 int startpos = (int) d.getStartPosition(); 330 int pos = (int) d.getPosition(); 331 int endpos = (int) d.getEndPosition(); 332 assertEquals("testPositionMissingStatement.diagspan", startpos, endpos); 333 assertEquals("testPositionMissingStatement.diagpref", startpos, pos); 334 } 335 336 @Test 337 void testPositionsSane1() throws IOException { 338 performPositionsSanityTest("package test; class Test { " + 339 "private void method() { " + 340 "java.util.List<? extends java.util.List<? extends String>> l; " + 341 "} }"); 342 } 343 344 @Test 345 void testPositionsSane2() throws IOException { 346 performPositionsSanityTest("package test; class Test { " + 347 "private void method() { " + 348 "java.util.List<? super java.util.List<? super String>> l; " + 349 "} }"); 350 } 351 352 @Test 353 void testPositionsSane3() throws IOException { 354 performPositionsSanityTest("package test; class Test { " + 355 "private void method() { " + 356 "java.util.List<? super java.util.List<?>> l; } }"); 357 } 358 359 private void performPositionsSanityTest(String code) throws IOException { 360 361 final List<Diagnostic<? extends JavaFileObject>> errors = 362 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 363 364 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 365 new DiagnosticListener<JavaFileObject>() { 366 367 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 368 errors.add(diagnostic); 369 } 370 }, null, null, Arrays.asList(new MyFileObject(code))); 371 372 final CompilationUnitTree cut = ct.parse().iterator().next(); 373 final Trees trees = Trees.instance(ct); 374 375 new TreeScanner<Void, Void>() { 376 377 private long parentStart = 0; 378 private long parentEnd = Integer.MAX_VALUE; 379 380 @Override 381 public Void scan(Tree node, Void p) { 382 if (node == null) { 383 return null; 384 } 385 386 long start = trees.getSourcePositions().getStartPosition(cut, node); 387 388 if (start == (-1)) { 389 return null; // synthetic tree 390 } 391 assertTrue(node.toString() + ":" + start + "/" + parentStart, 392 parentStart <= start); 393 394 long prevParentStart = parentStart; 395 396 parentStart = start; 397 398 long end = trees.getSourcePositions().getEndPosition(cut, node); 399 400 assertTrue(node.toString() + ":" + end + "/" + parentEnd, 401 end <= parentEnd); 402 403 long prevParentEnd = parentEnd; 404 405 parentEnd = end; 406 407 super.scan(node, p); 408 409 parentStart = prevParentStart; 410 parentEnd = prevParentEnd; 411 412 return null; 413 } 414 415 private void assertTrue(String message, boolean b) { 416 if (!b) fail(message); 417 } 418 }.scan(cut, null); 419 } 420 421 @Test 422 void testCorrectWildcardPositions1() throws IOException { 423 performWildcardPositionsTest("package test; import java.util.List; " + 424 "class Test { private void method() { List<? extends List<? extends String>> l; } }", 425 426 Arrays.asList("List<? extends List<? extends String>> l;", 427 "List<? extends List<? extends String>>", 428 "List", 429 "? extends List<? extends String>", 430 "List<? extends String>", 431 "List", 432 "? extends String", 433 "String")); 434 } 435 436 @Test 437 void testCorrectWildcardPositions2() throws IOException { 438 performWildcardPositionsTest("package test; import java.util.List; " 439 + "class Test { private void method() { List<? super List<? super String>> l; } }", 440 Arrays.asList("List<? super List<? super String>> l;", 441 "List<? super List<? super String>>", 442 "List", 443 "? super List<? super String>", 444 "List<? super String>", 445 "List", 446 "? super String", 447 "String")); 448 } 449 450 @Test 451 void testCorrectWildcardPositions3() throws IOException { 452 performWildcardPositionsTest("package test; import java.util.List; " + 453 "class Test { private void method() { List<? super List<?>> l; } }", 454 455 Arrays.asList("List<? super List<?>> l;", 456 "List<? super List<?>>", 457 "List", 458 "? super List<?>", 459 "List<?>", 460 "List", 461 "?")); 462 } 463 464 @Test 465 void testCorrectWildcardPositions4() throws IOException { 466 performWildcardPositionsTest("package test; import java.util.List; " + 467 "class Test { private void method() { " + 468 "List<? extends List<? extends List<? extends String>>> l; } }", 469 470 Arrays.asList("List<? extends List<? extends List<? extends String>>> l;", 471 "List<? extends List<? extends List<? extends String>>>", 472 "List", 473 "? extends List<? extends List<? extends String>>", 474 "List<? extends List<? extends String>>", 475 "List", 476 "? extends List<? extends String>", 477 "List<? extends String>", 478 "List", 479 "? extends String", 480 "String")); 481 } 482 483 @Test 484 void testCorrectWildcardPositions5() throws IOException { 485 performWildcardPositionsTest("package test; import java.util.List; " + 486 "class Test { private void method() { " + 487 "List<? extends List<? extends List<? extends String >>> l; } }", 488 Arrays.asList("List<? extends List<? extends List<? extends String >>> l;", 489 "List<? extends List<? extends List<? extends String >>>", 490 "List", 491 "? extends List<? extends List<? extends String >>", 492 "List<? extends List<? extends String >>", 493 "List", 494 "? extends List<? extends String >", 495 "List<? extends String >", 496 "List", 497 "? extends String", 498 "String")); 499 } 500 501 void performWildcardPositionsTest(final String code, 502 List<String> golden) throws IOException { 503 504 final List<Diagnostic<? extends JavaFileObject>> errors = 505 new LinkedList<Diagnostic<? extends JavaFileObject>>(); 506 507 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, 508 new DiagnosticListener<JavaFileObject>() { 509 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 510 errors.add(diagnostic); 511 } 512 }, null, null, Arrays.asList(new MyFileObject(code))); 513 514 final CompilationUnitTree cut = ct.parse().iterator().next(); 515 final List<String> content = new LinkedList<String>(); 516 final Trees trees = Trees.instance(ct); 517 518 new TreeScanner<Void, Void>() { 519 @Override 520 public Void scan(Tree node, Void p) { 521 if (node == null) { 522 return null; 523 } 524 long start = trees.getSourcePositions().getStartPosition(cut, node); 525 526 if (start == (-1)) { 527 return null; // synthetic tree 528 } 529 long end = trees.getSourcePositions().getEndPosition(cut, node); 530 String s = code.substring((int) start, (int) end); 531 content.add(s); 532 533 return super.scan(node, p); 534 } 535 }.scan(((MethodTree) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0)).getBody().getStatements().get(0), null); 536 537 assertEquals("performWildcardPositionsTest",golden.toString(), 538 content.toString()); 539 } 540 541 @Test 542 void testStartPositionForMethodWithoutModifiers() throws IOException { 543 544 String code = "package t; class Test { <T> void t() {} }"; 545 546 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 547 null, Arrays.asList(new MyFileObject(code))); 548 CompilationUnitTree cut = ct.parse().iterator().next(); 549 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 550 MethodTree mt = (MethodTree) clazz.getMembers().get(0); 551 Trees t = Trees.instance(ct); 552 int start = (int) t.getSourcePositions().getStartPosition(cut, mt); 553 int end = (int) t.getSourcePositions().getEndPosition(cut, mt); 554 555 assertEquals("testStartPositionForMethodWithoutModifiers", 556 "<T> void t() {}", code.substring(start, end)); 557 } 558 559 @Test 560 void testVariableInIfThen1() throws IOException { 561 562 String code = "package t; class Test { " + 563 "private static void t(String name) { " + 564 "if (name != null) String nn = name.trim(); } }"; 565 566 DiagnosticCollector<JavaFileObject> coll = 567 new DiagnosticCollector<JavaFileObject>(); 568 569 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 570 null, Arrays.asList(new MyFileObject(code))); 571 572 ct.parse(); 573 574 List<String> codes = new LinkedList<String>(); 575 576 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 577 codes.add(d.getCode()); 578 } 579 580 assertEquals("testVariableInIfThen1", 581 Arrays.<String>asList("compiler.err.variable.not.allowed"), 582 codes); 583 } 584 585 @Test 586 void testVariableInIfThen2() throws IOException { 587 588 String code = "package t; class Test { " + 589 "private static void t(String name) { " + 590 "if (name != null) class X {} } }"; 591 DiagnosticCollector<JavaFileObject> coll = 592 new DiagnosticCollector<JavaFileObject>(); 593 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 594 null, Arrays.asList(new MyFileObject(code))); 595 596 ct.parse(); 597 598 List<String> codes = new LinkedList<String>(); 599 600 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 601 codes.add(d.getCode()); 602 } 603 604 assertEquals("testVariableInIfThen2", 605 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 606 } 607 608 @Test 609 void testVariableInIfThen3() throws IOException { 610 611 String code = "package t; class Test { "+ 612 "private static void t() { " + 613 "if (true) abstract class F {} }}"; 614 DiagnosticCollector<JavaFileObject> coll = 615 new DiagnosticCollector<JavaFileObject>(); 616 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 617 null, Arrays.asList(new MyFileObject(code))); 618 619 ct.parse(); 620 621 List<String> codes = new LinkedList<String>(); 622 623 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 624 codes.add(d.getCode()); 625 } 626 627 assertEquals("testVariableInIfThen3", 628 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 629 } 630 631 @Test 632 void testVariableInIfThen4() throws IOException { 633 634 String code = "package t; class Test { "+ 635 "private static void t(String name) { " + 636 "if (name != null) interface X {} } }"; 637 DiagnosticCollector<JavaFileObject> coll = 638 new DiagnosticCollector<JavaFileObject>(); 639 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 640 null, Arrays.asList(new MyFileObject(code))); 641 642 ct.parse(); 643 644 List<String> codes = new LinkedList<String>(); 645 646 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 647 codes.add(d.getCode()); 648 } 649 650 assertEquals("testVariableInIfThen4", 651 Arrays.<String>asList("compiler.err.class.not.allowed"), codes); 652 } 653 654 @Test 655 void testVariableInIfThen5() throws IOException { 656 657 String code = "package t; class Test { "+ 658 "private static void t() { " + 659 "if (true) } }"; 660 DiagnosticCollector<JavaFileObject> coll = 661 new DiagnosticCollector<JavaFileObject>(); 662 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 663 null, Arrays.asList(new MyFileObject(code))); 664 665 ct.parse(); 666 667 List<String> codes = new LinkedList<String>(); 668 669 for (Diagnostic<? extends JavaFileObject> d : coll.getDiagnostics()) { 670 codes.add(d.getCode()); 671 } 672 673 assertEquals("testVariableInIfThen5", 674 Arrays.<String>asList("compiler.err.illegal.start.of.stmt"), 675 codes); 676 } 677 678 // see javac bug #6882235, NB bug #98234: 679 @Test 680 void testMissingExponent() throws IOException { 681 682 String code = "\nclass Test { { System.err.println(0e); } }"; 683 684 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 685 null, Arrays.asList(new MyFileObject(code))); 686 687 assertNotNull(ct.parse().iterator().next()); 688 } 689 690 @Test 691 void testTryResourcePos() throws IOException { 692 693 final String code = "package t; class Test { " + 694 "{ try (java.io.InputStream in = null) { } } }"; 695 696 CompilationUnitTree cut = getCompilationUnitTree(code); 697 698 new TreeScanner<Void, Void>() { 699 @Override 700 public Void visitVariable(VariableTree node, Void p) { 701 if ("in".contentEquals(node.getName())) { 702 JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node; 703 assertEquals("testTryResourcePos", "in = null) { } } }", 704 code.substring(var.pos)); 705 } 706 return super.visitVariable(node, p); 707 } 708 }.scan(cut, null); 709 } 710 711 @Test 712 void testVarPos() throws IOException { 713 714 final String code = "package t; class Test { " + 715 "{ java.io.InputStream in = null; } }"; 716 717 CompilationUnitTree cut = getCompilationUnitTree(code); 718 719 new TreeScanner<Void, Void>() { 720 721 @Override 722 public Void visitVariable(VariableTree node, Void p) { 723 if ("in".contentEquals(node.getName())) { 724 JCTree.JCVariableDecl var = (JCTree.JCVariableDecl) node; 725 assertEquals("testVarPos","in = null; } }", 726 code.substring(var.pos)); 727 } 728 return super.visitVariable(node, p); 729 } 730 }.scan(cut, null); 731 } 732 733 // expected erroneous tree: int x = y;(ERROR); 734 @Test 735 void testOperatorMissingError() throws IOException { 736 737 String code = "package test; public class ErrorTest { " 738 + "void method() { int x = y z } }"; 739 CompilationUnitTree cut = getCompilationUnitTree(code); 740 final List<String> values = new ArrayList<>(); 741 final List<String> expectedValues = 742 new ArrayList<>(Arrays.asList("[z]")); 743 744 new TreeScanner<Void, Void>() { 745 @Override 746 public Void visitErroneous(ErroneousTree node, Void p) { 747 values.add(getErroneousTreeValues(node).toString()); 748 return null; 749 750 } 751 }.scan(cut, null); 752 753 assertEquals("testOperatorMissingError: The Erroneous tree " 754 + "error values: " + values 755 + " do not match expected error values: " 756 + expectedValues, values, expectedValues); 757 } 758 759 // expected erroneous tree: String s = (ERROR); 760 @Test 761 void testMissingParenthesisError() throws IOException { 762 763 String code = "package test; public class ErrorTest { " 764 + "void f() {String s = new String; } }"; 765 CompilationUnitTree cut = getCompilationUnitTree(code); 766 final List<String> values = new ArrayList<>(); 767 final List<String> expectedValues = 768 new ArrayList<>(Arrays.asList("[new String()]")); 769 770 new TreeScanner<Void, Void>() { 771 @Override 772 public Void visitErroneous(ErroneousTree node, Void p) { 773 values.add(getErroneousTreeValues(node).toString()); 774 return null; 775 } 776 }.scan(cut, null); 777 778 assertEquals("testMissingParenthesisError: The Erroneous tree " 779 + "error values: " + values 780 + " do not match expected error values: " 781 + expectedValues, values, expectedValues); 782 } 783 784 // expected erroneous tree: package test; (ERROR)(ERROR) 785 @Test 786 void testMissingClassError() throws IOException { 787 788 String code = "package Test; clas ErrorTest { " 789 + "void f() {String s = new String(); } }"; 790 CompilationUnitTree cut = getCompilationUnitTree(code); 791 final List<String> values = new ArrayList<>(); 792 final List<String> expectedValues = 793 new ArrayList<>(Arrays.asList("[, clas]", "[]")); 794 795 new TreeScanner<Void, Void>() { 796 @Override 797 public Void visitErroneous(ErroneousTree node, Void p) { 798 values.add(getErroneousTreeValues(node).toString()); 799 return null; 800 } 801 }.scan(cut, null); 802 803 assertEquals("testMissingClassError: The Erroneous tree " 804 + "error values: " + values 805 + " do not match expected error values: " 806 + expectedValues, values, expectedValues); 807 } 808 809 // expected erroneous tree: void m1(int i) {(ERROR);{(ERROR);} 810 @Test 811 void testSwitchError() throws IOException { 812 813 String code = "package test; public class ErrorTest { " 814 + "int numDays; void m1(int i) { switchh {i} { case 1: " 815 + "numDays = 31; break; } } }"; 816 CompilationUnitTree cut = getCompilationUnitTree(code); 817 final List<String> values = new ArrayList<>(); 818 final List<String> expectedValues = 819 new ArrayList<>(Arrays.asList("[switchh]", "[i]")); 820 821 new TreeScanner<Void, Void>() { 822 @Override 823 public Void visitErroneous(ErroneousTree node, Void p) { 824 values.add(getErroneousTreeValues(node).toString()); 825 return null; 826 } 827 }.scan(cut, null); 828 829 assertEquals("testSwitchError: The Erroneous tree " 830 + "error values: " + values 831 + " do not match expected error values: " 832 + expectedValues, values, expectedValues); 833 } 834 835 // expected erroneous tree: class ErrorTest {(ERROR) 836 @Test 837 void testMethodError() throws IOException { 838 839 String code = "package Test; class ErrorTest { " 840 + "static final void f) {String s = new String(); } }"; 841 CompilationUnitTree cut = cut = getCompilationUnitTree(code); 842 843 final List<String> values = new ArrayList<>(); 844 final List<String> expectedValues = 845 new ArrayList<>(Arrays.asList("[\nstatic final void f();]")); 846 847 new TreeScanner<Void, Void>() { 848 @Override 849 public Void visitErroneous(ErroneousTree node, Void p) { 850 values.add(normalize(getErroneousTreeValues(node).toString())); 851 return null; 852 } 853 }.scan(cut, null); 854 855 assertEquals("testMethodError: The Erroneous tree " 856 + "error value: " + values 857 + " does not match expected error values: " 858 + expectedValues, values, expectedValues); 859 } 860 861 /* 862 * The following tests do not work just yet with nb-javac nor javac, 863 * they need further investigation, see CR: 7167356 864 */ 865 866 void testPositionBrokenSource126732a() throws IOException { 867 String[] commands = new String[]{ 868 "return Runnable()", 869 "do { } while (true)", 870 "throw UnsupportedOperationException()", 871 "assert true", 872 "1 + 1",}; 873 874 for (String command : commands) { 875 876 String code = "package test;\n" 877 + "public class Test {\n" 878 + " public static void test() {\n" 879 + " " + command + " {\n" 880 + " new Runnable() {\n" 881 + " };\n" 882 + " }\n" 883 + "}"; 884 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, 885 null, null, Arrays.asList(new MyFileObject(code))); 886 CompilationUnitTree cut = ct.parse().iterator().next(); 887 888 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 889 MethodTree method = (MethodTree) clazz.getMembers().get(0); 890 List<? extends StatementTree> statements = 891 method.getBody().getStatements(); 892 893 StatementTree ret = statements.get(0); 894 StatementTree block = statements.get(1); 895 896 Trees t = Trees.instance(ct); 897 int len = code.indexOf(command + " {") + (command + " ").length(); 898 assertEquals(command, len, 899 t.getSourcePositions().getEndPosition(cut, ret)); 900 assertEquals(command, len, 901 t.getSourcePositions().getStartPosition(cut, block)); 902 } 903 } 904 905 void testPositionBrokenSource126732b() throws IOException { 906 String[] commands = new String[]{ 907 "break", 908 "break A", 909 "continue ", 910 "continue A",}; 911 912 for (String command : commands) { 913 914 String code = "package test;\n" 915 + "public class Test {\n" 916 + " public static void test() {\n" 917 + " while (true) {\n" 918 + " " + command + " {\n" 919 + " new Runnable() {\n" 920 + " };\n" 921 + " }\n" 922 + " }\n" 923 + "}"; 924 925 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, 926 null, null, Arrays.asList(new MyFileObject(code))); 927 CompilationUnitTree cut = ct.parse().iterator().next(); 928 929 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 930 MethodTree method = (MethodTree) clazz.getMembers().get(0); 931 List<? extends StatementTree> statements = 932 ((BlockTree) ((WhileLoopTree) method.getBody().getStatements().get(0)).getStatement()).getStatements(); 933 934 StatementTree ret = statements.get(0); 935 StatementTree block = statements.get(1); 936 937 Trees t = Trees.instance(ct); 938 int len = code.indexOf(command + " {") + (command + " ").length(); 939 assertEquals(command, len, 940 t.getSourcePositions().getEndPosition(cut, ret)); 941 assertEquals(command, len, 942 t.getSourcePositions().getStartPosition(cut, block)); 943 } 944 } 945 946 void testStartPositionEnumConstantInit() throws IOException { 947 948 String code = "package t; enum Test { AAA; }"; 949 950 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 951 null, Arrays.asList(new MyFileObject(code))); 952 CompilationUnitTree cut = ct.parse().iterator().next(); 953 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 954 VariableTree enumAAA = (VariableTree) clazz.getMembers().get(0); 955 Trees t = Trees.instance(ct); 956 int start = (int) t.getSourcePositions().getStartPosition(cut, 957 enumAAA.getInitializer()); 958 959 assertEquals("testStartPositionEnumConstantInit", -1, start); 960 } 961 962 @Test 963 void testVoidLambdaParameter() throws IOException { 964 String code = "package t; class Test { " + 965 "Runnable r = (void v) -> { };" + 966 "}"; 967 DiagnosticCollector<JavaFileObject> coll = 968 new DiagnosticCollector<>(); 969 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, 970 null, Arrays.asList(new MyFileObject(code))); 971 972 CompilationUnitTree cut = ct.parse().iterator().next(); 973 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 974 VariableTree field = (VariableTree) clazz.getMembers().get(0); 975 976 assertEquals("actual kind: " + field.getInitializer().getKind(), 977 field.getInitializer().getKind(), 978 Kind.LAMBDA_EXPRESSION); 979 980 LambdaExpressionTree lambda = (LambdaExpressionTree) field.getInitializer(); 981 982 assertEquals("actual parameters: " + lambda.getParameters().size(), 983 lambda.getParameters().size(), 984 1); 985 986 Tree paramType = lambda.getParameters().get(0).getType(); 987 988 assertEquals("actual parameter type: " + paramType.getKind(), 989 paramType.getKind(), 990 Kind.PRIMITIVE_TYPE); 991 992 TypeKind primitiveTypeKind = ((PrimitiveTypeTree) paramType).getPrimitiveTypeKind(); 993 994 assertEquals("actual parameter type: " + primitiveTypeKind, 995 primitiveTypeKind, 996 TypeKind.VOID); 997 } 998 999 @Test //JDK-8065753 1000 void testWrongFirstToken() throws IOException { 1001 String code = "<"; 1002 String expectedErrors = "Test.java:1:1: compiler.err.expected3: class, interface, enum\n" + 1003 "1 error\n"; 1004 StringWriter out = new StringWriter(); 1005 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, 1006 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code))); 1007 1008 Result errorCode = ct.doCall(); 1009 assertEquals("the error code is not correct; actual:" + errorCode, Main.Result.ERROR, errorCode); 1010 String actualErrors = normalize(out.toString()); 1011 assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors); 1012 } 1013 1014 @Test //JDK-8205913 1015 void testForInit() throws IOException { 1016 String code = "class T { void t() { for (n : ns) { } } }"; 1017 String expectedErrors = "Test.java:1:27: compiler.err.bad.initializer: for-loop\n"; 1018 StringWriter out = new StringWriter(); 1019 JavacTask ct = (JavacTask) tool.getTask(out, fm, null, 1020 Arrays.asList("-XDrawDiagnostics"), null, Arrays.asList(new MyFileObject(code))); 1021 1022 Iterable<? extends CompilationUnitTree> cuts = ct.parse(); 1023 boolean[] foundVar = new boolean[1]; 1024 1025 new TreePathScanner<Void, Void>() { 1026 @Override public Void visitVariable(VariableTree vt, Void p) { 1027 assertNotNull(vt.getModifiers()); 1028 assertNotNull(vt.getType()); 1029 assertNotNull(vt.getName()); 1030 assertEquals("name should be <error>", "<error>", vt.getName().toString()); 1031 foundVar[0] = true; 1032 return super.visitVariable(vt, p); 1033 } 1034 }.scan(cuts, null); 1035 1036 if (!foundVar[0]) { 1037 fail("haven't found a variable"); 1038 } 1039 1040 String actualErrors = normalize(out.toString()); 1041 assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors); 1042 } 1043 1044 @Test 1045 void testCaseBodyStatements() throws IOException { 1046 String code = "class C {" + 1047 " void t(int i) {" + 1048 " switch (i) {" + 1049 " case 0 -> i++;" + 1050 " case 1 -> { i++; }" + 1051 " case 2 -> throw new RuntimeException();" + 1052 " case 3 -> if (true) ;" + 1053 " default -> i++;" + 1054 " }" + 1055 " switch (i) {" + 1056 " case 0: i++; break;" + 1057 " case 1: { i++; break;}" + 1058 " case 2: throw new RuntimeException();" + 1059 " case 3: if (true) ; break;" + 1060 " default: i++; break;" + 1061 " }" + 1062 " int j = switch (i) {" + 1063 " case 0 -> i + 1;" + 1064 " case 1 -> { break i + 1; }" + 1065 " default -> throw new RuntimeException();" + 1066 " };" + 1067 " int k = switch (i) {" + 1068 " case 0: break i + 1;" + 1069 " case 1: { break i + 1; }" + 1070 " default: throw new RuntimeException();" + 1071 " };" + 1072 " }" + 1073 "}"; 1074 String expectedErrors = "Test.java:1:178: compiler.err.switch.case.unexpected.statement\n"; 1075 StringWriter out = new StringWriter(); 1076 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, 1077 Arrays.asList("-XDrawDiagnostics", "--enable-preview", "-source", "12"), 1078 null, Arrays.asList(new MyFileObject(code))); 1079 1080 CompilationUnitTree cut = ct.parse().iterator().next(); 1081 Trees trees = Trees.instance(ct); 1082 List<String> spans = new ArrayList<>(); 1083 1084 new TreePathScanner<Void, Void>() { 1085 @Override 1086 public Void visitCase(CaseTree tree, Void v) { 1087 if (tree.getBody() != null) { 1088 int start = (int) trees.getSourcePositions().getStartPosition(cut, tree.getBody()); 1089 int end = (int) trees.getSourcePositions().getEndPosition(cut, tree.getBody()); 1090 spans.add(code.substring(start, end)); 1091 } else { 1092 spans.add("<null>"); 1093 } 1094 return super.visitCase(tree, v); 1095 } 1096 }.scan(cut, null); 1097 1098 List<String> expectedSpans = List.of( 1099 "i++;", "{ i++; }", "throw new RuntimeException();", "if (true) ;", "i++;", 1100 "<null>", "<null>", "<null>", "<null>", "<null>", 1101 "i + 1"/*TODO semicolon?*/, "{ break i + 1; }", "throw new RuntimeException();", 1102 "<null>", "<null>", "<null>"); 1103 assertEquals("the error spans are not correct; actual:" + spans, expectedSpans, spans); 1104 String toString = normalize(cut.toString()); 1105 String expectedToString = 1106 "\n" + 1107 "class C {\n" + 1108 " \n" + 1109 " void t(int i) {\n" + 1110 " switch (i) {\n" + 1111 " case 0 -> i++;\n" + 1112 " case 1 -> {\n" + 1113 " i++;\n" + 1114 " }\n" + 1115 " case 2 -> throw new RuntimeException();\n" + 1116 " case 3 -> if (true) ;\n" + 1117 " default -> i++;\n" + 1118 " }\n" + 1119 " switch (i) {\n" + 1120 " case 0:\n" + 1121 " i++;\n" + 1122 " break;\n" + 1123 " \n" + 1124 " case 1:\n" + 1125 " {\n" + 1126 " i++;\n" + 1127 " break;\n" + 1128 " }\n" + 1129 " \n" + 1130 " case 2:\n" + 1131 " throw new RuntimeException();\n" + 1132 " \n" + 1133 " case 3:\n" + 1134 " if (true) ;\n" + 1135 " break;\n" + 1136 " \n" + 1137 " default:\n" + 1138 " i++;\n" + 1139 " break;\n" + 1140 " \n" + 1141 " }\n" + 1142 " int j = switch (i) {\n" + 1143 " case 0 -> break i + 1;\n" + 1144 " case 1 -> {\n" + 1145 " break i + 1;\n" + 1146 " }\n" + 1147 " default -> throw new RuntimeException();\n" + 1148 " };\n" + 1149 " int k = switch (i) {\n" + 1150 " case 0:\n" + 1151 " break i + 1;\n" + 1152 " \n" + 1153 " case 1:\n" + 1154 " {\n" + 1155 " break i + 1;\n" + 1156 " }\n" + 1157 " \n" + 1158 " default:\n" + 1159 " throw new RuntimeException();\n" + 1160 " \n" + 1161 " };\n" + 1162 " }\n" + 1163 "}"; 1164 System.err.println("toString:"); 1165 System.err.println(toString); 1166 System.err.println("expectedToString:"); 1167 System.err.println(expectedToString); 1168 assertEquals("the error spans are not correct; actual:" + toString, expectedToString, toString); 1169 String actualErrors = normalize(out.toString()); 1170 assertEquals("the error message is not correct, actual: " + actualErrors, expectedErrors, actualErrors); 1171 } 1172 1173 @Test 1174 void testTypeParamsWithoutMethod() throws IOException { 1175 assert tool != null; 1176 1177 String code = "package test; class Test { /**javadoc*/ |public <T> |}"; 1178 String[] parts = code.split("\\|"); 1179 1180 code = parts[0] + parts[1] + parts[2]; 1181 1182 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1183 null, Arrays.asList(new MyFileObject(code))); 1184 Trees trees = Trees.instance(ct); 1185 SourcePositions pos = trees.getSourcePositions(); 1186 CompilationUnitTree cut = ct.parse().iterator().next(); 1187 ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); 1188 ErroneousTree err = (ErroneousTree) clazz.getMembers().get(0); 1189 MethodTree method = (MethodTree) err.getErrorTrees().get(0); 1190 1191 final int methodStart = parts[0].length(); 1192 final int methodEnd = parts[0].length() + parts[1].length(); 1193 assertEquals("testTypeParamsWithoutMethod", 1194 methodStart, pos.getStartPosition(cut, method)); 1195 assertEquals("testTypeParamsWithoutMethod", 1196 methodEnd, pos.getEndPosition(cut, method)); 1197 1198 TreePath path2Method = new TreePath(new TreePath(new TreePath(cut), clazz), method); 1199 String javadoc = trees.getDocComment(path2Method); 1200 1201 if (!"javadoc".equals(javadoc)) { 1202 throw new AssertionError("Expected javadoc not found, actual javadoc: " + javadoc); 1203 } 1204 } 1205 1206 @Test 1207 void testAnalyzeParensWithComma1() throws IOException { 1208 assert tool != null; 1209 1210 String code = "package test; class Test { FI fi = |(s, |"; 1211 String[] parts = code.split("\\|", 3); 1212 1213 code = parts[0] + parts[1] + parts[2]; 1214 1215 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1216 null, Arrays.asList(new MyFileObject(code))); 1217 Trees trees = Trees.instance(ct); 1218 SourcePositions pos = trees.getSourcePositions(); 1219 CompilationUnitTree cut = ct.parse().iterator().next(); 1220 boolean[] found = new boolean[1]; 1221 1222 new TreeScanner<Void, Void>() { 1223 @Override 1224 public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) { 1225 found[0] = true; 1226 int lambdaStart = parts[0].length(); 1227 int lambdaEnd = parts[0].length() + parts[1].length(); 1228 assertEquals("testAnalyzeParensWithComma1", 1229 lambdaStart, pos.getStartPosition(cut, tree)); 1230 assertEquals("testAnalyzeParensWithComma1", 1231 lambdaEnd, pos.getEndPosition(cut, tree)); 1232 return null; 1233 } 1234 }.scan(cut, null); 1235 1236 assertTrue("testAnalyzeParensWithComma1", found[0]); 1237 } 1238 1239 @Test 1240 void testAnalyzeParensWithComma2() throws IOException { 1241 assert tool != null; 1242 1243 String code = "package test; class Test { FI fi = |(s, o)|"; 1244 String[] parts = code.split("\\|", 3); 1245 1246 code = parts[0] + parts[1] + parts[2]; 1247 1248 JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, null, null, 1249 null, Arrays.asList(new MyFileObject(code))); 1250 Trees trees = Trees.instance(ct); 1251 SourcePositions pos = trees.getSourcePositions(); 1252 CompilationUnitTree cut = ct.parse().iterator().next(); 1253 boolean[] found = new boolean[1]; 1254 1255 new TreeScanner<Void, Void>() { 1256 @Override 1257 public Void visitLambdaExpression(LambdaExpressionTree tree, Void v) { 1258 found[0] = true; 1259 int lambdaStart = parts[0].length(); 1260 int lambdaEnd = parts[0].length() + parts[1].length(); 1261 assertEquals("testAnalyzeParensWithComma2", 1262 lambdaStart, pos.getStartPosition(cut, tree)); 1263 assertEquals("testAnalyzeParensWithComma2", 1264 lambdaEnd, pos.getEndPosition(cut, tree)); 1265 return null; 1266 } 1267 }.scan(cut, null); 1268 1269 assertTrue("testAnalyzeParensWithComma2", found[0]); 1270 } 1271 1272 void run(String[] args) throws Exception { 1273 int passed = 0, failed = 0; 1274 final Pattern p = (args != null && args.length > 0) 1275 ? Pattern.compile(args[0]) 1276 : null; 1277 for (Method m : this.getClass().getDeclaredMethods()) { 1278 boolean selected = (p == null) 1279 ? m.isAnnotationPresent(Test.class) 1280 : p.matcher(m.getName()).matches(); 1281 if (selected) { 1282 try { 1283 m.invoke(this, (Object[]) null); 1284 System.out.println(m.getName() + ": OK"); 1285 passed++; 1286 } catch (Throwable ex) { 1287 System.out.printf("Test %s failed: %s %n", m, ex.getCause()); 1288 failed++; 1289 } 1290 } 1291 } 1292 System.out.printf("Passed: %d, Failed %d%n", passed, failed); 1293 if (failed > 0) { 1294 throw new RuntimeException("Tests failed: " + failed); 1295 } 1296 if (passed == 0 && failed == 0) { 1297 throw new AssertionError("No test(s) selected: passed = " + 1298 passed + ", failed = " + failed + " ??????????"); 1299 } 1300 } 1301 } 1302 1303 abstract class TestCase { 1304 1305 void assertEquals(String message, int i, int pos) { 1306 if (i != pos) { 1307 fail(message); 1308 } 1309 } 1310 1311 void assertFalse(String message, boolean bvalue) { 1312 if (bvalue == true) { 1313 fail(message); 1314 } 1315 } 1316 1317 void assertTrue(String message, boolean bvalue) { 1318 if (bvalue == false) { 1319 fail(message); 1320 } 1321 } 1322 1323 void assertEquals(String message, int i, long l) { 1324 if (i != l) { 1325 fail(message + ":" + i + ":" + l); 1326 } 1327 } 1328 1329 void assertEquals(String message, Object o1, Object o2) { 1330 if (o1 != null && o2 != null && !o1.equals(o2)) { 1331 fail(message); 1332 } 1333 if (o1 == null && o2 != null) { 1334 fail(message); 1335 } 1336 } 1337 1338 void assertNotNull(Object o) { 1339 if (o == null) { 1340 fail(); 1341 } 1342 } 1343 1344 void fail() { 1345 fail("test failed"); 1346 } 1347 1348 void fail(String message) { 1349 throw new RuntimeException(message); 1350 } 1351 1352 /** 1353 * Indicates that the annotated method is a test method. 1354 */ 1355 @Retention(RetentionPolicy.RUNTIME) 1356 @Target(ElementType.METHOD) 1357 public @interface Test {} 1358 }