| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.junit; |
| |
| import org.netbeans.modules.junit.api.JUnitVersion; |
| import com.sun.source.tree.AnnotationTree; |
| import com.sun.source.tree.BlockTree; |
| import com.sun.source.tree.ClassTree; |
| import com.sun.source.tree.ExpressionTree; |
| import com.sun.source.tree.MethodTree; |
| import com.sun.source.tree.ModifiersTree; |
| import com.sun.source.tree.StatementTree; |
| import com.sun.source.tree.Tree; |
| import com.sun.source.tree.TypeParameterTree; |
| import com.sun.source.tree.VariableTree; |
| import com.sun.source.util.TreePath; |
| import com.sun.source.util.Trees; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.EnumSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.AnnotationValue; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.ExecutableElement; |
| import javax.lang.model.element.Modifier; |
| import javax.lang.model.element.Name; |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.type.TypeKind; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.util.Types; |
| import org.netbeans.api.java.source.ElementHandle; |
| import org.netbeans.api.java.source.TreeMaker; |
| import org.netbeans.api.java.source.WorkingCopy; |
| import static javax.lang.model.element.Modifier.PUBLIC; |
| import static javax.lang.model.element.Modifier.PROTECTED; |
| import static javax.lang.model.element.Modifier.PRIVATE; |
| import static javax.lang.model.element.Modifier.STATIC; |
| |
| /** |
| * |
| * @author Marian Petras |
| */ |
| final class JUnit4TestGenerator extends AbstractTestGenerator { |
| |
| /** */ |
| static final String ANN_BEFORE_CLASS = "org.junit.BeforeClass"; //NOI18N |
| /** */ |
| static final String ANN_AFTER_CLASS = "org.junit.AfterClass"; //NOI18N |
| /** */ |
| static final String ANN_BEFORE = "org.junit.Before"; //NOI18N |
| /** */ |
| static final String ANN_AFTER = "org.junit.After"; //NOI18N |
| /** */ |
| static final String ANN_TEST = "org.junit.Test"; //NOI18N |
| /** */ |
| private static final String ANN_RUN_WITH = "org.junit.runner.RunWith";//NOI18N |
| /** */ |
| private static final String ANN_SUITE = "org.junit.runners.Suite"; //NOI18N |
| /** */ |
| private static final String ANN_SUITE_MEMBERS = "SuiteClasses"; //NOI18N |
| /** */ |
| private static final String BEFORE_CLASS_METHOD_NAME = "setUpClass";//NOI18N |
| /** */ |
| private static final String AFTER_CLASS_METHOD_NAME = "tearDownClass";//NOI18N |
| /** */ |
| private static final String BEFORE_METHOD_NAME = "setUp"; //NOI18N |
| /** */ |
| private static final String AFTER_METHOD_NAME = "tearDown"; //NOI18N |
| |
| /** |
| */ |
| JUnit4TestGenerator(TestGeneratorSetup setup) { |
| super(setup, JUnitVersion.JUNIT4); |
| } |
| |
| /** |
| */ |
| JUnit4TestGenerator(TestGeneratorSetup setup, |
| List<ElementHandle<TypeElement>> srcTopClassHandles, |
| List<String>suiteMembers, |
| boolean isNewTestClass) { |
| super(setup, srcTopClassHandles, suiteMembers, isNewTestClass, JUnitVersion.JUNIT4); |
| } |
| |
| |
| /** |
| */ |
| @Override |
| protected ClassTree composeNewTestClass(WorkingCopy workingCopy, |
| String name, |
| List<? extends Tree> members) { |
| final TreeMaker maker = workingCopy.getTreeMaker(); |
| ModifiersTree modifiers = maker.Modifiers( |
| Collections.<Modifier>singleton(PUBLIC)); |
| return maker.Class( |
| modifiers, //modifiers |
| name, //name |
| Collections.<TypeParameterTree>emptyList(),//type params |
| null, //extends |
| Collections.<ExpressionTree>emptyList(), //implements |
| members); //members |
| } |
| |
| /** |
| */ |
| @Override |
| protected List<? extends Tree> generateInitMembers(WorkingCopy workingCopy) { |
| if (!setup.isGenerateBefore() && !setup.isGenerateAfter() |
| && !setup.isGenerateBeforeClass() && !setup.isGenerateAfterClass()) { |
| return Collections.<Tree>emptyList(); |
| } |
| |
| List<MethodTree> result = new ArrayList<MethodTree>(4); |
| if (setup.isGenerateBeforeClass()) { |
| result.add( |
| generateInitMethod(BEFORE_CLASS_METHOD_NAME, ANN_BEFORE_CLASS, true, workingCopy)); |
| } |
| if (setup.isGenerateAfterClass()) { |
| result.add( |
| generateInitMethod(AFTER_CLASS_METHOD_NAME, ANN_AFTER_CLASS, true, workingCopy)); |
| } |
| if (setup.isGenerateBefore()) { |
| result.add( |
| generateInitMethod(BEFORE_METHOD_NAME, ANN_BEFORE, false, workingCopy)); |
| } |
| if (setup.isGenerateAfter()) { |
| result.add( |
| generateInitMethod(AFTER_METHOD_NAME, ANN_AFTER, false, workingCopy)); |
| } |
| return result; |
| } |
| |
| /** |
| */ |
| @Override |
| protected ClassTree generateMissingInitMembers(ClassTree tstClass, |
| TreePath tstClassTreePath, |
| WorkingCopy workingCopy) { |
| if (!setup.isGenerateBefore() && !setup.isGenerateAfter() |
| && !setup.isGenerateBeforeClass() && !setup.isGenerateAfterClass()) { |
| return tstClass; |
| } |
| |
| ClassMap classMap = ClassMap.forClass(tstClass, tstClassTreePath, |
| workingCopy.getTrees()); |
| |
| if ((!setup.isGenerateBefore() || classMap.containsBefore()) |
| && (!setup.isGenerateAfter() || classMap.containsAfter()) |
| && (!setup.isGenerateBeforeClass() || classMap.containsBeforeClass()) |
| && (!setup.isGenerateAfterClass() || classMap.containsAfterClass())) { |
| return tstClass; |
| } |
| |
| final TreeMaker maker = workingCopy.getTreeMaker(); |
| |
| List<? extends Tree> tstMembersOrig = tstClass.getMembers(); |
| List<Tree> tstMembers = new ArrayList<Tree>(tstMembersOrig.size() + 4); |
| tstMembers.addAll(tstMembersOrig); |
| |
| generateMissingInitMembers(tstMembers, classMap, workingCopy); |
| |
| ClassTree newClass = maker.Class( |
| tstClass.getModifiers(), |
| tstClass.getSimpleName(), |
| tstClass.getTypeParameters(), |
| tstClass.getExtendsClause(), |
| (List<? extends ExpressionTree>) tstClass.getImplementsClause(), |
| tstMembers); |
| return newClass; |
| } |
| |
| /** |
| */ |
| @Override |
| protected boolean generateMissingInitMembers(List<Tree> tstMembers, |
| ClassMap clsMap, |
| WorkingCopy workingCopy) { |
| boolean modified = false; |
| |
| if (setup.isGenerateBeforeClass() && !clsMap.containsBeforeClass()) { |
| int targetIndex; |
| if (clsMap.containsAfterClass()) { |
| targetIndex = clsMap.getAfterClassIndex(); |
| } else { |
| int beforeIndex = clsMap.getBeforeIndex(); |
| int afterIndex = clsMap.getAfterIndex(); |
| if ((beforeIndex != -1) && (afterIndex != -1)) { |
| targetIndex = Math.min(beforeIndex, afterIndex); |
| } else { |
| /* |
| * if (beforeIndex != -1) |
| * targetIndex = beforeIndex; |
| * else if (afterIndex != -1) |
| * targetIndex = afterIndex; |
| * else |
| * targetIndex = -1; |
| */ |
| targetIndex = Math.max(beforeIndex, afterIndex); |
| } |
| } |
| addInitMethod(BEFORE_CLASS_METHOD_NAME, |
| ANN_BEFORE_CLASS, |
| true, |
| targetIndex, |
| tstMembers, |
| clsMap, |
| workingCopy); |
| modified = true; |
| } |
| if (setup.isGenerateAfterClass() && !clsMap.containsAfterClass()) { |
| int targetIndex; |
| if (clsMap.containsBeforeClass()) { |
| targetIndex = clsMap.getBeforeClassIndex() + 1; |
| } else { |
| int beforeIndex = clsMap.getBeforeIndex(); |
| int afterIndex = clsMap.getAfterIndex(); |
| if ((beforeIndex != -1) && (afterIndex != -1)) { |
| targetIndex = Math.min(beforeIndex, afterIndex); |
| } else { |
| targetIndex = Math.max(beforeIndex, afterIndex); |
| } |
| } |
| addInitMethod(AFTER_CLASS_METHOD_NAME, |
| ANN_AFTER_CLASS, |
| true, |
| targetIndex, |
| tstMembers, |
| clsMap, |
| workingCopy); |
| modified = true; |
| } |
| if (setup.isGenerateBefore() && !clsMap.containsBefore()) { |
| int targetIndex; |
| if (clsMap.containsAfter()) { |
| targetIndex = clsMap.getAfterIndex(); |
| } else { |
| int beforeClassIndex = clsMap.getBeforeClassIndex(); |
| int afterClassIndex = clsMap.getAfterClassIndex(); |
| |
| /* |
| * if ((beforeClassIndex != -1) && (afterClassIndex != -1)) |
| * targetIndex = Math.max(beforeClassIndex, afterClassIndex) + 1; |
| * else if (beforeClassIndex != -1) |
| * targetIndex = beforeClassIndex + 1; |
| * else if (afterClassIndex != -1) |
| * targetIndex = afterClassIndex + 1; |
| * else |
| * targetIndex = -1 |
| */ |
| targetIndex = Math.max(beforeClassIndex, afterClassIndex); |
| if (targetIndex != -1) { |
| targetIndex++; |
| } |
| } |
| addInitMethod(BEFORE_METHOD_NAME, |
| ANN_BEFORE, |
| false, |
| targetIndex, |
| tstMembers, |
| clsMap, |
| workingCopy); |
| modified = true; |
| } |
| if (setup.isGenerateAfter() && !clsMap.containsAfter()) { |
| int targetIndex; |
| if (clsMap.containsBefore()) { |
| targetIndex = clsMap.getBeforeIndex() + 1; |
| } else { |
| int beforeClassIndex = clsMap.getBeforeClassIndex(); |
| int afterClassIndex = clsMap.getAfterClassIndex(); |
| targetIndex = Math.max(beforeClassIndex, afterClassIndex); |
| if (targetIndex != -1) { |
| targetIndex++; |
| } |
| } |
| addInitMethod(AFTER_METHOD_NAME, |
| ANN_AFTER, |
| false, |
| targetIndex, |
| tstMembers, |
| clsMap, |
| workingCopy); |
| modified = true; |
| } |
| |
| return modified; |
| } |
| |
| /** |
| */ |
| private void addInitMethod(String methodName, |
| String annotationClassName, |
| boolean isStatic, |
| int targetIndex, |
| List<Tree> clsMembers, |
| ClassMap clsMap, |
| WorkingCopy workingCopy) { |
| MethodTree initMethod = generateInitMethod(methodName, |
| annotationClassName, |
| isStatic, |
| workingCopy); |
| |
| if (targetIndex == -1) { |
| targetIndex = getPlaceForFirstInitMethod(clsMap); |
| } |
| |
| if (targetIndex != -1) { |
| clsMembers.add(targetIndex, initMethod); |
| } else { |
| clsMembers.add(initMethod); |
| } |
| clsMap.addNoArgMethod(methodName, annotationClassName, targetIndex); |
| } |
| |
| /** |
| * Generates a set-up or a tear-down method. |
| * The generated method will have no arguments, void return type |
| * and a declaration that it may throw {@code java.lang.Exception}. |
| * The method will have a declared protected member access. |
| * The method contains call of the corresponding super method, i.e. |
| * {@code super.setUp()} or {@code super.tearDown()}. |
| * |
| * @param methodName name of the method to be created |
| * @return created method |
| * @see http://junit.sourceforge.net/javadoc/junit/framework/TestCase.html |
| * methods {@code setUp()} and {@code tearDown()} |
| */ |
| private MethodTree generateInitMethod(String methodName, |
| String annotationClassName, |
| boolean isStatic, |
| WorkingCopy workingCopy) { |
| Set<Modifier> methodModifiers |
| = isStatic ? createModifierSet(PUBLIC, STATIC) |
| : Collections.<Modifier>singleton(PUBLIC); |
| ModifiersTree modifiers = createModifiersTree(annotationClassName, |
| methodModifiers, |
| workingCopy); |
| TreeMaker maker = workingCopy.getTreeMaker(); |
| BlockTree methodBody = maker.Block( |
| Collections.<StatementTree>emptyList(), |
| false); |
| MethodTree method = maker.Method( |
| modifiers, // modifiers |
| methodName, // name |
| maker.PrimitiveType(TypeKind.VOID), // return type |
| Collections.<TypeParameterTree>emptyList(), // type params |
| Collections.<VariableTree>emptyList(), // parameters |
| Collections.<ExpressionTree>singletonList( |
| maker.Identifier("Exception")), // throws...//NOI18N |
| methodBody, |
| null); // default value |
| return method; |
| } |
| |
| /** |
| */ |
| @Override |
| protected void generateMissingPostInitMethods(TreePath tstClassTreePath, |
| List<Tree> tstMembers, |
| ClassMap clsMap, |
| WorkingCopy workingCopy) { |
| /* no post-init methods */ |
| } |
| |
| /** |
| */ |
| @Override |
| protected MethodTree composeNewTestMethod(String testMethodName, |
| BlockTree testMethodBody, |
| List<ExpressionTree> throwsList, |
| WorkingCopy workingCopy) { |
| TreeMaker maker = workingCopy.getTreeMaker(); |
| return maker.Method( |
| createModifiersTree(ANN_TEST, |
| createModifierSet(PUBLIC), |
| workingCopy), |
| testMethodName, |
| maker.PrimitiveType(TypeKind.VOID), |
| Collections.<TypeParameterTree>emptyList(), |
| Collections.<VariableTree>emptyList(), |
| throwsList, |
| testMethodBody, |
| null); //default value - used by annotations |
| } |
| |
| /** |
| */ |
| @Override |
| protected ClassTree finishSuiteClass(ClassTree tstClass, |
| TreePath tstClassTreePath, |
| List<Tree> tstMembers, |
| List<String> suiteMembers, |
| boolean membersChanged, |
| ClassMap classMap, |
| WorkingCopy workingCopy) { |
| |
| ModifiersTree currModifiers = tstClass.getModifiers(); |
| ModifiersTree modifiers = fixSuiteClassModifiers(tstClass, |
| tstClassTreePath, |
| currModifiers, |
| suiteMembers, |
| workingCopy); |
| if (!membersChanged) { |
| if (modifiers != currModifiers) { |
| workingCopy.rewrite(currModifiers, modifiers); |
| } |
| return tstClass; |
| } |
| |
| return workingCopy.getTreeMaker().Class( |
| modifiers, |
| tstClass.getSimpleName(), |
| tstClass.getTypeParameters(), |
| tstClass.getExtendsClause(), |
| (List<? extends ExpressionTree>) tstClass.getImplementsClause(), |
| tstMembers); |
| } |
| |
| /** |
| * Keeps or modifies annotations and modifiers of the given suite class. |
| * Modifiers are modified such that the class is public. |
| * The list of annotations is modified such that it contains |
| * the following annotations: |
| * <pre><code>RunWith(Suite.class) |
| * @SuiteRunner.Suite({...})</code></pre> |
| * with members of the suite in place of the <code>{...}</code> list. |
| * |
| * @param tstClass class whose modifiers and anntations are to be modified |
| * @param tstClassTreePath tree path to the class from the compilation unit |
| * @param modifiers current modifiers and annotations |
| * @param suiteMembers list of class names that should be contained |
| * in the test suite |
| * @return {@code ModifiersTree} object containing the modified set |
| * of class modifiers and annotations, or {@code null} |
| * if no modifications were necessary |
| */ |
| private ModifiersTree fixSuiteClassModifiers(ClassTree tstClass, |
| TreePath tstClassTreePath, |
| ModifiersTree modifiers, |
| List<String> suiteMembers, |
| WorkingCopy workingCopy) { |
| boolean flagsModified = false; |
| |
| Set<Modifier> currFlags = modifiers.getFlags(); |
| Set<Modifier> flags = currFlags.isEmpty() ? EnumSet.noneOf(Modifier.class) : EnumSet.copyOf(currFlags); |
| flagsModified |= flags.remove(PRIVATE); |
| flagsModified |= flags.remove(PROTECTED); |
| flagsModified |= flags.add(PUBLIC); |
| if (!flagsModified) { |
| flags = currFlags; |
| } |
| |
| |
| boolean annotationListModified = false; |
| |
| List<? extends AnnotationTree> currAnnotations = modifiers.getAnnotations(); |
| List<? extends AnnotationTree> annotations; |
| if (currAnnotations.isEmpty()) { |
| List<AnnotationTree> newAnnotations = new ArrayList<AnnotationTree>(2); |
| newAnnotations.add(createRunWithSuiteAnnotation(workingCopy)); |
| newAnnotations.add(createSuiteAnnotation(suiteMembers, workingCopy)); |
| annotations = newAnnotations; |
| |
| annotationListModified = true; |
| } else { |
| Trees trees = workingCopy.getTrees(); |
| Element classElement = trees.getElement(tstClassTreePath); |
| List<? extends AnnotationMirror> annMirrors |
| = classElement.getAnnotationMirrors(); |
| assert annMirrors.size() == currAnnotations.size(); |
| |
| |
| int index = -1, runWithIndex = -1, suiteClassesIndex = -1; |
| for (AnnotationMirror annMirror : annMirrors) { |
| index++; |
| Element annElement = annMirror.getAnnotationType().asElement(); |
| assert annElement instanceof TypeElement; |
| TypeElement annTypeElem = (TypeElement) annElement; |
| Name annFullName = annTypeElem.getQualifiedName(); |
| |
| if ((runWithIndex == -1) && annFullName.contentEquals(ANN_RUN_WITH)) { |
| runWithIndex = index; |
| } else if ((suiteClassesIndex == -1) |
| && annFullName.contentEquals(ANN_SUITE + '.' + ANN_SUITE_MEMBERS)) { |
| suiteClassesIndex = index; |
| } |
| } |
| |
| AnnotationTree runWithSuiteAnn; |
| if ((runWithIndex == -1) || !checkRunWithSuiteAnnotation( |
| annMirrors.get(runWithIndex), |
| workingCopy)) { |
| runWithSuiteAnn = createRunWithSuiteAnnotation(workingCopy); |
| } else { |
| runWithSuiteAnn = currAnnotations.get(runWithIndex); |
| } |
| |
| AnnotationTree suiteClassesAnn; |
| if ((suiteClassesIndex == -1) || !checkSuiteMembersAnnotation( |
| annMirrors.get(suiteClassesIndex), |
| suiteMembers, |
| workingCopy)) { |
| suiteClassesAnn = createSuiteAnnotation(suiteMembers, workingCopy); |
| } else { |
| suiteClassesAnn = currAnnotations.get(suiteClassesIndex); |
| } |
| |
| if ((runWithIndex != -1) && (suiteClassesIndex != -1)) { |
| if (runWithSuiteAnn != currAnnotations.get(runWithIndex)) { |
| workingCopy.rewrite( |
| currAnnotations.get(runWithIndex), |
| runWithSuiteAnn); |
| } |
| if (suiteClassesAnn != currAnnotations.get(suiteClassesIndex)) { |
| workingCopy.rewrite( |
| currAnnotations.get(suiteClassesIndex), |
| suiteClassesAnn); |
| } |
| annotations = currAnnotations; |
| } else { |
| List<AnnotationTree> newAnnotations |
| = new ArrayList<AnnotationTree>(currAnnotations.size() + 2); |
| if ((runWithIndex == -1) && (suiteClassesIndex == -1)) { |
| |
| /* |
| * put the @RunWith(...) and @Suite.SuiteClasses(...) |
| * annotations in front of other annotations |
| */ |
| newAnnotations.add(runWithSuiteAnn); |
| newAnnotations.add(suiteClassesAnn); |
| if (!currAnnotations.isEmpty()) { |
| newAnnotations.addAll(currAnnotations); |
| } |
| } else { |
| newAnnotations.addAll(currAnnotations); |
| if (runWithIndex == -1) { |
| assert suiteClassesIndex != 1; |
| |
| /* |
| * put the @RunWith(...) annotation |
| * just before the Suite.SuiteClasses(...) annotation |
| */ |
| newAnnotations.add(suiteClassesIndex, runWithSuiteAnn); |
| } else { |
| assert runWithIndex != -1; |
| |
| /* |
| * put the @Suite.SuiteClasses(...) annotation |
| * just after the @RunWith(...) annotation |
| */ |
| newAnnotations.add(runWithIndex + 1, suiteClassesAnn); |
| } |
| } |
| annotations = newAnnotations; |
| |
| annotationListModified = true; |
| } |
| } |
| |
| if (!flagsModified && !annotationListModified) { |
| return modifiers; |
| } |
| |
| return workingCopy.getTreeMaker().Modifiers(flags, annotations); |
| } |
| |
| /** |
| * Checks that the given annotation is of type |
| * <code>{@value #ANN_RUN_WITH}</code> and contains argument |
| * <code>{@value #ANN_SUITE}{@literal .class}</code>. |
| * |
| * @param annMirror annotation to be checked |
| * @return {@code true} if the annotation meets the described criteria, |
| * {@code false} otherwise |
| */ |
| private boolean checkRunWithSuiteAnnotation(AnnotationMirror annMirror, |
| WorkingCopy workingCopy) { |
| Map<? extends ExecutableElement,? extends AnnotationValue> annParams |
| = annMirror.getElementValues(); |
| |
| if (annParams.size() != 1) { |
| return false; |
| } |
| |
| AnnotationValue annValue = annParams.values().iterator().next(); |
| Name annValueClsName = getAnnotationValueClassName(annValue, |
| workingCopy.getTypes()); |
| return annValueClsName != null |
| ? annValueClsName.contentEquals(ANN_SUITE) |
| : false; |
| } |
| |
| /** |
| * Checks that the given annotation is of type |
| * <code>{@value #ANN_SUITE}.{@value #ANN_SUITE_MEMBERS}</code> |
| * and contains the given list of classes as (the only) argument, |
| * in the same order. |
| * |
| * @param annMirror annotation to be checked |
| * @param suiteMembers list of fully qualified class names denoting |
| * content of the test suite |
| * @return {@code true} if the annotation meets the described criteria, |
| * {@code false} otherwise |
| */ |
| private boolean checkSuiteMembersAnnotation(AnnotationMirror annMirror, |
| List<String> suiteMembers, |
| WorkingCopy workingCopy) { |
| Map<? extends ExecutableElement,? extends AnnotationValue> annParams |
| = annMirror.getElementValues(); |
| |
| if (annParams.size() != 1) { |
| return false; |
| } |
| |
| AnnotationValue annValue = annParams.values().iterator().next(); |
| Object value = annValue.getValue(); |
| if (value instanceof java.util.List) { |
| List<? extends AnnotationValue> items |
| = (List<? extends AnnotationValue>) value; |
| |
| if (items.size() != suiteMembers.size()) { |
| return false; |
| } |
| |
| Types types = workingCopy.getTypes(); |
| Iterator<String> suiteMembersIt = suiteMembers.iterator(); |
| for (AnnotationValue item : items) { |
| Name suiteMemberName = getAnnotationValueClassName(item, types); |
| if (suiteMemberName == null) { |
| return false; |
| } |
| if (!suiteMemberName.contentEquals(suiteMembersIt.next())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Returns fully qualified class name of a class given to an annotation |
| * as (the only) argument. |
| * |
| * @param annValue annotation value |
| * @return fully qualified name of a class represented by the given |
| * annotation value, or {@code null} if the annotation value |
| * does not represent a class |
| */ |
| private Name getAnnotationValueClassName(AnnotationValue annValue, |
| Types types) { |
| Object value = annValue.getValue(); |
| if (value instanceof TypeMirror) { |
| TypeMirror typeMirror = (TypeMirror) value; |
| Element typeElement = types.asElement(typeMirror); |
| if (typeElement.getKind() == ElementKind.CLASS) { |
| return ((TypeElement) typeElement).getQualifiedName(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Creates annotation <code>@org.junit.runner.RunWith</code>. |
| * |
| * @return created annotation |
| */ |
| private AnnotationTree createRunWithSuiteAnnotation( |
| WorkingCopy workingCopy) { |
| TreeMaker maker = workingCopy.getTreeMaker(); |
| |
| /* @RunWith(Suite.class) */ |
| return maker.Annotation( |
| getClassIdentifierTree(ANN_RUN_WITH, workingCopy), |
| Collections.<ExpressionTree>singletonList( |
| maker.MemberSelect( |
| getClassIdentifierTree(ANN_SUITE, workingCopy), |
| "class"))); //NOI18N |
| } |
| |
| /** |
| * Creates annotation |
| * <code>@org.junit.runners.Suite.SuiteClasses({...})</code>. |
| * |
| * @param suiteMembers fully qualified names of classes to be included |
| * in the test suite |
| * @param created annotation |
| */ |
| private AnnotationTree createSuiteAnnotation(List<String> suiteMembers, |
| WorkingCopy workingCopy) { |
| final TreeMaker maker = workingCopy.getTreeMaker(); |
| |
| List<ExpressionTree> suiteMemberExpressions |
| = new ArrayList<ExpressionTree>(suiteMembers.size()); |
| for (String suiteMember : suiteMembers) { |
| suiteMemberExpressions.add( |
| maker.MemberSelect( |
| getClassIdentifierTree(suiteMember, workingCopy), |
| "class")); //NOI18N |
| } |
| |
| /* @Suite.SuiteClasses({TestA.class, TestB.class, ...}) */ |
| return maker.Annotation( |
| maker.MemberSelect( |
| getClassIdentifierTree(ANN_SUITE, workingCopy), |
| ANN_SUITE_MEMBERS), |
| Collections.singletonList( |
| maker.NewArray( |
| null, //do not generate "new Class[]" |
| Collections.<ExpressionTree>emptyList(), |
| suiteMemberExpressions))); |
| } |
| |
| } |