1 19 20 package org.netbeans.modules.junit; 21 22 import com.sun.source.tree.BlockTree; 23 import com.sun.source.tree.ClassTree; 24 import com.sun.source.tree.ExpressionTree; 25 import com.sun.source.tree.MethodInvocationTree; 26 import com.sun.source.tree.MethodTree; 27 import com.sun.source.tree.ModifiersTree; 28 import com.sun.source.tree.ReturnTree; 29 import com.sun.source.tree.StatementTree; 30 import com.sun.source.tree.Tree; 31 import com.sun.source.tree.TypeParameterTree; 32 import com.sun.source.tree.VariableTree; 33 import com.sun.source.util.TreePath; 34 import com.sun.source.util.Trees; 35 import java.util.ArrayList ; 36 import java.util.Collections ; 37 import java.util.List ; 38 import javax.lang.model.element.Element; 39 import javax.lang.model.element.ExecutableElement; 40 import javax.lang.model.element.Modifier; 41 import javax.lang.model.element.TypeElement; 42 import javax.lang.model.type.TypeKind; 43 import javax.lang.model.type.TypeMirror; 44 import javax.lang.model.util.ElementFilter; 45 import javax.lang.model.util.Elements; 46 import javax.lang.model.util.Types; 47 import org.netbeans.api.java.source.ElementHandle; 48 import org.netbeans.api.java.source.TreeMaker; 49 import org.netbeans.api.java.source.WorkingCopy; 50 import org.openide.ErrorManager; 51 import static javax.lang.model.element.Modifier.ABSTRACT; 52 import static javax.lang.model.element.Modifier.PRIVATE; 53 import static javax.lang.model.element.Modifier.PROTECTED; 54 import static javax.lang.model.element.Modifier.PUBLIC; 55 import static javax.lang.model.element.Modifier.STATIC; 56 57 62 final class JUnit3TestGenerator extends AbstractTestGenerator { 63 64 66 JUnit3TestGenerator(TestGeneratorSetup setup) { 67 super(setup); 68 } 69 70 72 JUnit3TestGenerator(TestGeneratorSetup setup, 73 List <ElementHandle<TypeElement>> srcTopClassHandles, 74 List <String >suiteMembers, 75 boolean isNewTestClass) { 76 super(setup, srcTopClassHandles, suiteMembers, isNewTestClass); 77 } 78 79 80 81 private TypeElement testTypeElem; 82 83 private TypeElement testCaseTypeElem; 84 85 private TypeElement testSuiteTypeElem; 86 87 88 90 protected ClassTree composeNewTestClass(WorkingCopy workingCopy, 91 String name, 92 List <? extends Tree> members) { 93 final TreeMaker maker = workingCopy.getTreeMaker(); 94 ModifiersTree modifiers = maker.Modifiers( 95 Collections.<Modifier>singleton(PUBLIC)); 96 TypeElement testCaseType = getTestCaseTypeElem(workingCopy.getElements()); 97 Tree extendsClause = (testCaseType != null) 98 ? maker.QualIdent(testCaseType) 99 : maker.Identifier("junit.framework.TestCase"); return maker.Class( 101 modifiers, name, Collections.<TypeParameterTree>emptyList(), extendsClause, Collections.<ExpressionTree>emptyList(), members); } 108 109 111 protected List <? extends Tree> generateInitMembers(WorkingCopy workingCopy) { 112 if (!setup.isGenerateSetUp() && !setup.isGenerateTearDown()) { 113 return Collections.<Tree>emptyList(); 114 } 115 116 final TreeMaker maker = workingCopy.getTreeMaker(); 117 List <MethodTree> result = new ArrayList <MethodTree>(2); 118 if (setup.isGenerateSetUp()) { 119 result.add(generateInitMethod("setUp", maker)); } 121 if (setup.isGenerateTearDown()) { 122 result.add(generateInitMethod("tearDown", maker)); } 124 return result; 125 } 126 127 129 protected ClassTree generateMissingInitMembers(ClassTree tstClass, 130 TreePath tstClassTreePath, 131 WorkingCopy workingCopy) { 132 if (!setup.isGenerateSetUp() && !setup.isGenerateTearDown() 133 && !setup.isGenerateSuiteClasses()) { 134 return tstClass; 135 } 136 137 ClassMap classMap = ClassMap.forClass(tstClass, tstClassTreePath, workingCopy.getTrees()); 138 139 if ((!setup.isGenerateSetUp() || classMap.containsSetUp()) 140 && (!setup.isGenerateTearDown() || classMap.containsTearDown()) 141 && (!setup.isGenerateSuiteClasses() || classMap.containsNoArgMethod("suite"))) { return tstClass; 143 } 144 145 List <? extends Tree> tstMembersOrig = tstClass.getMembers(); 146 List <Tree> tstMembers = new ArrayList <Tree>(tstMembersOrig.size() + 2); 147 tstMembers.addAll(tstMembersOrig); 148 149 generateMissingInitMembers(tstMembers, classMap, workingCopy); 150 generateTestClassSuiteMethod(tstClassTreePath, tstMembers, classMap, 151 workingCopy); 152 153 ClassTree newClass = workingCopy.getTreeMaker().Class( 154 tstClass.getModifiers(), 155 tstClass.getSimpleName(), 156 tstClass.getTypeParameters(), 157 tstClass.getExtendsClause(), 158 (List <? extends ExpressionTree>) tstClass.getImplementsClause(), 159 tstMembers); 160 return newClass; 161 } 162 163 165 protected boolean generateMissingInitMembers(List <Tree> tstMembers, 166 ClassMap clsMap, 167 WorkingCopy workingCopy) { 168 TreeMaker treeMaker = workingCopy.getTreeMaker(); 169 170 boolean modified = false; 171 if (setup.isGenerateSetUp() && !clsMap.containsSetUp()) { 172 addInitMethod("setUp", clsMap.getTearDownIndex(), 174 tstMembers, 175 clsMap, 176 treeMaker); 177 modified = true; 178 } 179 if (setup.isGenerateTearDown() && !clsMap.containsTearDown()) { 180 int setUpIndex = clsMap.getSetUpIndex(); 181 addInitMethod("tearDown", (setUpIndex != -1) ? setUpIndex + 1 : -1, 183 tstMembers, 184 clsMap, 185 treeMaker); 186 modified = true; 187 } 188 return modified; 189 } 190 191 207 private void addInitMethod(String methodName, 208 int targetIndex, 209 List <Tree> clsMembers, 210 ClassMap clsMap, 211 TreeMaker treeMaker) { 212 MethodTree initMethod = generateInitMethod(methodName, treeMaker); 213 214 if (targetIndex == -1) { 215 targetIndex = getPlaceForFirstInitMethod(clsMap); 216 } 217 218 if (targetIndex != -1) { 219 clsMembers.add(targetIndex, initMethod); 220 } else { 221 clsMembers.add(initMethod); 222 } 223 clsMap.addNoArgMethod(methodName, targetIndex); 224 } 225 226 239 protected MethodTree generateInitMethod(String methodName, 240 TreeMaker maker) { 241 ModifiersTree modifiers = maker.Modifiers( 242 Collections.<Modifier>singleton(PROTECTED)); 243 ExpressionTree superMethodCall = maker.MethodInvocation( 244 Collections.<ExpressionTree>emptyList(), maker.MemberSelect( 246 maker.Identifier("super"), methodName), Collections.<ExpressionTree>emptyList()); 248 BlockTree methodBody = maker.Block( 249 Collections.<StatementTree>singletonList( 250 maker.ExpressionStatement(superMethodCall)), 251 false); 252 MethodTree method = maker.Method( 253 modifiers, methodName, maker.PrimitiveType(TypeKind.VOID), Collections.<TypeParameterTree>emptyList(), Collections.<VariableTree>emptyList(), Collections.<ExpressionTree>singletonList( 259 maker.Identifier("Exception")), methodBody, 261 null); return method; 263 } 264 265 267 protected void generateMissingPostInitMethods(TreePath tstClassTreePath, 268 List <Tree> tstMembers, 269 ClassMap clsMap, 270 WorkingCopy workingCopy) { 271 if (setup.isGenerateSuiteClasses()) { 272 generateTestClassSuiteMethod(tstClassTreePath, 273 tstMembers, 274 clsMap, 275 workingCopy); 276 } 277 } 278 279 281 protected MethodTree composeNewTestMethod(String testMethodName, 282 BlockTree testMethodBody, 283 List <ExpressionTree> throwsList, 284 WorkingCopy workingCopy) { 285 TreeMaker maker = workingCopy.getTreeMaker(); 286 return maker.Method( 287 maker.Modifiers(createModifierSet(PUBLIC)), 288 testMethodName, 289 maker.PrimitiveType(TypeKind.VOID), 290 Collections.<TypeParameterTree>emptyList(), 291 Collections.<VariableTree>emptyList(), 292 throwsList, 293 testMethodBody, 294 null); } 296 297 299 protected ClassTree finishSuiteClass(ClassTree tstClass, 300 TreePath tstClassTreePath, 301 List <Tree> tstMembers, 302 List <String > suiteMembers, 303 boolean membersChanged, 304 ClassMap classMap, 305 WorkingCopy workingCopy) { 306 MethodTree suiteMethod = generateSuiteMethod( 307 tstClass.getSimpleName().toString(), 308 suiteMembers, 309 workingCopy); 310 if (suiteMethod != null) { 311 int suiteMethodIndex = classMap.findNoArgMethod("suite"); if (suiteMethodIndex != -1) { 313 tstMembers.set(suiteMethodIndex, suiteMethod); } else { 315 int targetIndex; 316 if (classMap.containsInitializers()) { 317 targetIndex = classMap.getLastInitializerIndex() + 1; 318 } else if (classMap.containsMethods()) { 319 targetIndex = classMap.getFirstMethodIndex(); 320 } else if (classMap.containsNestedClasses()) { 321 targetIndex = classMap.getFirstNestedClassIndex(); 322 } else { 323 targetIndex = classMap.size(); 324 } 325 if (targetIndex == classMap.size()) { 326 tstMembers.add(suiteMethod); 327 } else { 328 tstMembers.add(targetIndex, suiteMethod); 329 } 330 classMap.addNoArgMethod("suite", targetIndex); } 332 membersChanged = true; 333 } 334 335 340 if (!membersChanged) { 341 return tstClass; 342 } 343 344 return workingCopy.getTreeMaker().Class( 345 tstClass.getModifiers(), 346 tstClass.getSimpleName(), 347 tstClass.getTypeParameters(), 348 tstClass.getExtendsClause(), 349 (List <? extends ExpressionTree>) tstClass.getImplementsClause(), 350 tstMembers); 351 } 352 353 358 private MethodTree generateSuiteMethod(String suiteName, 359 List <String > members, 360 WorkingCopy workingCopy) { 361 final Types types = workingCopy.getTypes(); 362 final Elements elements = workingCopy.getElements(); 363 final TreeMaker maker = workingCopy.getTreeMaker(); 364 365 TypeElement testSuiteElem = getTestSuiteTypeElem(elements); 366 if (testSuiteElem == null) { 367 return null; 368 } 369 370 TypeElement testTypeElem = getTestTypeElem(elements); 371 if (testTypeElem == null) { 372 return null; 373 } 374 TypeMirror testType = testTypeElem.asType(); 375 376 List <StatementTree> bodyContent 377 = new ArrayList <StatementTree>(members.size() + 2); 378 379 380 381 VariableTree suiteObjInit = maker.Variable( 382 maker.Modifiers(noModifiers()), 383 "suite", maker.QualIdent(testSuiteElem), 385 maker.NewClass( 386 null, Collections.<ExpressionTree>emptyList(), maker.QualIdent(testSuiteElem), Collections.singletonList( maker.Literal(TestUtil.getSimpleName(suiteName))), 391 null)); 393 bodyContent.add(suiteObjInit); 394 395 for (String className : members) { 396 TypeElement classElem = elements.getTypeElement(className); 397 if ((classElem != null) && containsSuiteMethod( 398 classElem, 399 elements, types, 400 testType)) { 401 402 403 404 MethodInvocationTree suiteMethodCall, methodCall; 405 suiteMethodCall = maker.MethodInvocation( 406 Collections.<ExpressionTree>emptyList(), 407 maker.MemberSelect(maker.QualIdent(classElem), 408 "suite"), Collections.<ExpressionTree>emptyList()); 410 methodCall = maker.MethodInvocation( 411 Collections.<ExpressionTree>emptyList(), 412 maker.MemberSelect(maker.Identifier("suite"), "addTest"), Collections.singletonList(suiteMethodCall)); 415 416 bodyContent.add(maker.ExpressionStatement(methodCall)); 417 } 418 } 419 420 421 422 bodyContent.add(maker.Return(maker.Identifier("suite"))); 424 425 return maker.Method( 426 maker.Modifiers(createModifierSet(PUBLIC, STATIC)), 427 "suite", maker.QualIdent(testTypeElem), Collections.<TypeParameterTree>emptyList(), Collections.<VariableTree>emptyList(), Collections.<ExpressionTree>emptyList(), maker.Block(bodyContent, false), null); } 435 436 449 private boolean containsSuiteMethod(TypeElement typeElement, 450 Elements elements, 451 Types types, 452 TypeMirror testType) { 453 List <ExecutableElement> allMethods 454 = ElementFilter.methodsIn(elements.getAllMembers(typeElement)); 455 for (ExecutableElement method : allMethods) { 456 if (method.getSimpleName().contentEquals("suite") && method.getParameters().isEmpty()) { 458 return method.getModifiers().contains(Modifier.STATIC) 459 && types.isSameType(method.getReturnType(), 460 testType); 461 } 462 } 463 return false; 464 } 465 466 468 private boolean generateTestClassSuiteMethod(TreePath tstClassTreePath, 469 List <Tree> tstMembers, 470 ClassMap clsMap, 471 WorkingCopy workingCopy) { 472 if (!setup.isGenerateSuiteClasses() 473 || clsMap.containsNoArgMethod("suite")) { return false; 475 } 476 477 final TreeMaker maker = workingCopy.getTreeMaker(); 478 final Elements elements = workingCopy.getElements(); 479 final Trees trees = workingCopy.getTrees(); 480 481 Element tstClassElem = trees.getElement(tstClassTreePath); 482 assert tstClassElem != null; 483 484 List <StatementTree> bodyContent = new ArrayList <StatementTree>(4); 485 486 487 488 489 VariableTree suiteVar = maker.Variable( 490 maker.Modifiers(noModifiers()), 491 "suite", maker.QualIdent(getTestSuiteTypeElem(elements)), 493 maker.NewClass( 494 null, Collections.<ExpressionTree>emptyList(), 496 maker.QualIdent(getTestSuiteTypeElem(elements)), 497 Collections.singletonList( 498 maker.MemberSelect(maker.QualIdent(tstClassElem), 499 "class")), null)); 502 bodyContent.add(suiteVar); 503 504 505 506 507 508 List <TypeElement> nestedClassElems 509 = ElementFilter.typesIn(tstClassElem.getEnclosedElements()); 510 if (!nestedClassElems.isEmpty()) { 511 for (TypeElement nestedClassElem : nestedClassElems) { 512 if (TestUtil.isClassTest(workingCopy, nestedClassElem)) { 513 514 515 516 517 MethodInvocationTree arg = maker.MethodInvocation( 518 Collections.<ExpressionTree>emptyList(), 519 maker.MemberSelect( 520 maker.QualIdent(nestedClassElem), 521 "suite"), Collections.<ExpressionTree>emptyList()); 523 524 525 MethodInvocationTree methodCall = maker.MethodInvocation( 526 Collections.<ExpressionTree>emptyList(), 527 maker.MemberSelect( 528 maker.Identifier("suite"), "addTest"), Collections.singletonList(arg)); 531 532 bodyContent.add(maker.ExpressionStatement(methodCall)); 533 } 534 } 535 } 536 537 538 539 ReturnTree returnStmt 540 = maker.Return(maker.Identifier("suite")); bodyContent.add(returnStmt); 542 543 MethodTree suiteMethod = maker.Method( 544 maker.Modifiers(createModifierSet(PUBLIC, STATIC)), 545 "suite", maker.QualIdent(getTestTypeElem(elements)), Collections.<TypeParameterTree>emptyList(), Collections.<VariableTree>emptyList(), Collections.<ExpressionTree>emptyList(), maker.Block(bodyContent, false), null, (TypeElement) tstClassElem); 553 554 int targetIndex; 555 if (clsMap.containsMethods()) { 556 targetIndex = clsMap.getFirstMethodIndex(); } else if (clsMap.containsNestedClasses()) { 558 targetIndex = clsMap.getFirstNestedClassIndex(); } else { 560 targetIndex = clsMap.size(); } 562 563 if (targetIndex == clsMap.size()) { 564 tstMembers.add(suiteMethod); 565 } else { 566 tstMembers.add(targetIndex, suiteMethod); 567 } 568 clsMap.addNoArgMethod("suite", targetIndex); 570 return true; 571 } 572 573 575 private TypeElement getTestTypeElem(Elements elements) { 576 if (testTypeElem == null) { 577 testTypeElem = getElemForClassName( 578 "junit.framework.Test", elements); 580 } 581 return testTypeElem; 582 } 583 584 586 private TypeElement getTestCaseTypeElem(Elements elements) { 587 if (testCaseTypeElem == null) { 588 testCaseTypeElem = getElemForClassName( 589 "junit.framework.TestCase", elements); 591 } 592 return testCaseTypeElem; 593 } 594 595 597 private TypeElement getTestSuiteTypeElem(Elements elements) { 598 if (testSuiteTypeElem == null) { 599 testSuiteTypeElem = getElemForClassName( 600 "junit.framework.TestSuite", elements); 602 } 603 return testSuiteTypeElem; 604 } 605 606 608 private static TypeElement getElemForClassName(String className, 609 Elements elements) { 610 TypeElement elem = elements.getTypeElement(className); 611 if (elem == null) { 612 ErrorManager.getDefault().log( 613 ErrorManager.ERROR, 614 "Could not find TypeElement for " + className); } 616 return elem; 617 } 618 619 } 620 | Popular Tags |