All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.testng.ClassMap Maven / Gradle / Ivy

There is a newer version: RELEASE230
Show newest version
/*
 * 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.testng;

import com.sun.source.tree.ClassTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;

/**
 * Data structure that holds overview of class' members and their positions
 * within the class.
 * 

To get an instance for a class, use static method * {@link #forClass}.

* * @author Marian Petras */ final class ClassMap { private static final int SETUP_POS_INDEX = 0; private static final int TEARDOWN_POS_INDEX = 1; private static final int FIRST_METHOD_POS_INDEX = 2; private static final int LAST_INIT_POS_INDEX = 3; private static final int FIRST_NESTED_POS_INDEX = 4; private static final int BEFORE_POS_INDEX = 5; private static final int AFTER_POS_INDEX = 6; private static final int BEFORE_CLASS_POS_INDEX = 7; private static final int AFTER_CLASS_POS_INDEX = 8; // private static final String JUNIT4_PKG_PREFIX = "org.junit."; //NOI18N private static final String TESTNG_PKG_PREFIX = "org.testng.annotations."; //NOI18N private static final int[] EMPTY_INT_ARRAY = new int[0]; /** */ private final List signatures; /** */ private final int[] positions; /** Creates a new instance of ClassMap */ private ClassMap(List signatures) { this.signatures = signatures; } { positions = new int[9]; for (int i = 0; i < positions.length; i++) { positions[i] = -1; } } /** * * @exception java.lang.IllegalArgumentException * if any of the arguments is {@code null} * or if the specified {@code ClassTree} is not a leaf * of the specified {@code TreePath} */ static ClassMap forClass(ClassTree cls, TreePath clsTreePath, Trees trees) { if (cls == null) { throw new IllegalArgumentException("ClassTree: null"); //NOI18N } if (clsTreePath == null) { throw new IllegalArgumentException("TreePath: null"); //NOI18N } if (clsTreePath.getLeaf() != cls) { throw new IllegalArgumentException( "given ClassTree is not leaf of the given TreePath"); //NOI18N } List members = cls.getMembers(); if (members.isEmpty()) { return new ClassMap(new ArrayList()); } List entries = new ArrayList(members.size()); ClassMap map = new ClassMap(entries); int index = 0; for (Tree member : members) { String signature; switch (member.getKind()) { case BLOCK: signature = "* "; //NOI18N map.setLastInitializerIndex(index); break; case VARIABLE: signature = "- "; //NOI18N break; case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: ClassTree clazz = (ClassTree) member; signature = "[ " + clazz.getSimpleName(); //NOI18N if (map.getFirstNestedClassIndex() == -1) { map.setFirstNestedClassIndex(index); } break; case METHOD: MethodTree method = (MethodTree) member; boolean hasParams = !method.getParameters().isEmpty(); Name methodName = method.getName(); if (methodName.contentEquals("")) { //NOI18N signature = hasParams ? "*+" : "* "; //NOI18N map.setLastInitializerIndex(index); } else { if (!hasParams) { if ((map.getSetUpIndex() == -1) && methodName.contentEquals("setUp")) { //NOI18N map.setSetUpIndex(index); } if ((map.getTearDownIndex() == -1) && methodName.contentEquals("tearDown")) { //NOI18N map.setTearDownIndex(index); } } signature = (hasParams ? "!+" : "! ") //NOI18N + methodName.toString(); if (map.getFirstMethodIndex() == -1) { map.setFirstMethodIndex(index); } /* annotations: */ if (!method.getModifiers().getAnnotations().isEmpty()) { TreePath methodTreePath = new TreePath(clsTreePath, method); Element methodElement = trees.getElement(methodTreePath); for (AnnotationMirror annMirror : methodElement.getAnnotationMirrors()) { Element annElem = annMirror.getAnnotationType().asElement(); String fullName = ((TypeElement) annElem).getQualifiedName().toString(); if (fullName.startsWith(TESTNG_PKG_PREFIX)) { String shortName = fullName.substring(TESTNG_PKG_PREFIX.length()); int posIndex; if (shortName.equals("BeforeMethod")) { //NOI18N posIndex = BEFORE_POS_INDEX; } else if (shortName.equals("AfterMethod")) { //NOI18N posIndex = AFTER_POS_INDEX; } else if (shortName.equals("BeforeClass")) { //NOI18N posIndex = BEFORE_CLASS_POS_INDEX; } else if (shortName.equals("AfterClass")) { //NOI18N posIndex = AFTER_CLASS_POS_INDEX; } else { continue; //next annotation } if (map.positions[posIndex] == -1) { map.positions[posIndex] = index; } } } } } break; default: signature = "x "; //NOI18N } entries.add(signature); index++; } return map; } /** */ int getSetUpIndex() { return positions[SETUP_POS_INDEX]; } /** */ private void setSetUpIndex(int setUpIndex) { positions[SETUP_POS_INDEX] = setUpIndex; } /** */ int getTearDownIndex() { return positions[TEARDOWN_POS_INDEX]; } /** */ private void setTearDownIndex(int tearDownIndex) { positions[TEARDOWN_POS_INDEX] = tearDownIndex; } /** * Returns an index of a method annotated with annotation * {@code org.testng.annotations.BeforeMethod}. If there are more such methods * index of any of these methods may be returned. * * @return index of a {@code @Before}-annotated method, * or {@code -1} if there is no such method */ int getBeforeIndex() { return positions[BEFORE_POS_INDEX]; } /** */ private void setBeforeIndex(int index) { positions[BEFORE_POS_INDEX] = index; } /** * Returns an index of a method annotated with annotation * {@code org.testng.annotations.AfterMethod}. If there are more such methods * index of any of these methods may be returned. * * @return index of a {@code @After}-annotated method, * or {@code -1} if there is no such method */ int getAfterIndex() { return positions[AFTER_POS_INDEX]; } /** */ private void setAfterIndex(int index) { positions[AFTER_POS_INDEX] = index; } /** * Returns an index of a method annotated with annotation * {@code org.testng.annotations.BeforeClass}. If there are more such methods * index of any of these methods may be returned. * * @return index of a {@code @BeforeClass}-annotated method, * or {@code -1} if there is no such method */ int getBeforeClassIndex() { return positions[BEFORE_CLASS_POS_INDEX]; } /** */ private void setBeforeClassIndex(int index) { positions[BEFORE_CLASS_POS_INDEX] = index; } /** * Returns an index of a method annotated with annotation * {@code org.testng.annotations.AfterClass}. If there are more such methods * index of any of these methods may be returned. * * @return index of a {@code @AfterClass}-annotated method, * or {@code -1} if there is no such method */ int getAfterClassIndex() { return positions[AFTER_CLASS_POS_INDEX]; } /** */ private void setAfterClassIndex(int index) { positions[AFTER_CLASS_POS_INDEX] = index; } /** */ int getFirstMethodIndex() { return positions[FIRST_METHOD_POS_INDEX]; } /** */ private void setFirstMethodIndex(int firstMethodIndex) { positions[FIRST_METHOD_POS_INDEX] = firstMethodIndex; } /** */ int getFirstNestedClassIndex() { return positions[FIRST_NESTED_POS_INDEX]; } /** */ private void setFirstNestedClassIndex(int firstNestedClassIndex) { positions[FIRST_NESTED_POS_INDEX] = firstNestedClassIndex; } /** */ int getLastInitializerIndex() { return positions[LAST_INIT_POS_INDEX]; } /** */ private void setLastInitializerIndex(int lastInitializerIndex) { positions[LAST_INIT_POS_INDEX] = lastInitializerIndex; } /** */ boolean containsSetUp() { return getSetUpIndex() != -1; } /** */ boolean containsTearDown() { return getTearDownIndex() != -1; } /** */ boolean containsBefore() { return getBeforeIndex() != -1; } /** */ boolean containsAfter() { return getAfterIndex() != -1; } /** */ boolean containsBeforeClass() { return getBeforeClassIndex() != -1; } /** */ boolean containsAfterClass() { return getAfterClassIndex() != -1; } /** */ boolean containsNoArgMethod(String name) { return findNoArgMethod(name) != -1; } /** */ boolean containsMethods() { return getFirstMethodIndex() != -1; } /** */ boolean containsInitializers() { return getLastInitializerIndex() != -1; } /** */ boolean containsNestedClasses() { return getFirstNestedClassIndex() != -1; } /** */ int findNoArgMethod(String name) { if (!containsMethods()) { return -1; } if (name.equals("setUp")) { //NOI18N return getSetUpIndex(); } if (name.equals("tearDown")) { //NOI18N return getTearDownIndex(); } return signatures.indexOf("! " + name); //NOI18N } /** */ void addNoArgMethod(String name) { addNoArgMethod(name, size()); } /** */ void addNoArgMethod(String name, int index) { int currSize = size(); if (index > currSize) { throw new IndexOutOfBoundsException("index: " + index //NOI18N + ", size: " + currSize);//NOI18N } String signature = "! " + name; //NOI18N if (index != currSize) { signatures.add(index, signature); shiftPositions(index, 1); } else { signatures.add(signature); //NOI18N } if (name.equals("setUp")) { //NOI18N setSetUpIndex(index); } else if (name.equals("tearDown")) { //NOI18N setTearDownIndex(index); } if (getFirstMethodIndex() == -1) { setFirstMethodIndex(index); } } /** */ void addNoArgMethod(String name, String annotationName) { addNoArgMethod(name, annotationName, size()); } /** */ void addNoArgMethod(String name, String annotationName, int index) { addNoArgMethod(name, index); if (annotationName.equals(TestGenerator.ANN_BEFORE)) { setBeforeIndex(index); } else if (annotationName.equals(TestGenerator.ANN_AFTER)) { setAfterIndex(index); } else if (annotationName.equals(TestGenerator.ANN_BEFORE_CLASS)) { setBeforeClassIndex(index); } else if (annotationName.equals(TestGenerator.ANN_AFTER_CLASS)) { setAfterClassIndex(index); } } /** */ void removeNoArgMethod(int index) { if (index < 0) { throw new IndexOutOfBoundsException("negative index (" //NOI18N + index + ')'); } if (index >= size()) { throw new IndexOutOfBoundsException("index: " + index //NOI18N + ", size: " + size()); //NOI18N } String signature = signatures.get(index); if (!signature.startsWith("! ")) { //NOI18N throw new IllegalArgumentException( "not a no-arg method at the given index (" //NOI18N + index + ')'); } if (index == getSetUpIndex()) { setSetUpIndex(-1); } else if (index == getTearDownIndex()) { setTearDownIndex(-1); } if (index == getFirstMethodIndex()) { int currSize = size(); if (index == (currSize - 1)) { setFirstMethodIndex(-1); } else { int newFirstMethodIndex = -1; int memberIndex = index + 1; for (String sign : signatures.subList(index + 1, currSize)) { if (sign.startsWith("! ")) { newFirstMethodIndex = memberIndex; break; } memberIndex++; } setFirstMethodIndex(newFirstMethodIndex); } } shiftPositions(index + 1, -1); } /** * Returns names of all no-argument methods. * * @return list of names of no-argument methods * in the order of the methods in the source code */ List getNoArgMethods() { if (!containsMethods()) { return Collections.emptyList(); } List result = new ArrayList(signatures.size()); for (String signature : signatures) { if (signature.startsWith("! ")) { //NOI18N result.add(signature.substring(2)); } } return result.isEmpty() ? Collections.emptyList() : result; } /** */ void addNestedClass(String name) { int currSize = size(); signatures.add("[ " + name); //NOI18N if (getFirstNestedClassIndex() == -1) { setFirstNestedClassIndex(currSize); } } /** * Returns names of classes contained in the class corresponding to this * {@code ClassMap}. Both nested classes (static) and inner classes are * taken into account. Anonymous inner classes are ignored. * * @return list of names of nested and inner classes in the order * of the classes in the source code, */ List getNestedClasses() { int firstIndex = getFirstNestedClassIndex(); if (firstIndex == -1) { return Collections.emptyList(); } assert signatures.get(firstIndex).charAt(0) == '['; String firstNestedClass = signatures.get(firstIndex).substring(2); final int size = size(); if (firstIndex == (size - 1)) { return Collections.singletonList(firstNestedClass); } List result = null; int startIndex = firstIndex + 1; Iterator it = signatures.subList(startIndex, size).iterator(); for (int index = startIndex; it.hasNext(); index++) { String signature = it.next(); if (signature.charAt(0) == '[') { if (result == null) { int initialCapacity = Math.min(4, size - index + 1); result = new ArrayList(initialCapacity); result.add(firstNestedClass); } result.add(signature.substring(2)); } } if (result == null) { result = Collections.singletonList(firstNestedClass); } return result; } /** * Returns indexes (positions) of classes contained in the class * corresponding to this {@code ClassMap}. Both nested classes (static) * and inner classes are taken into account. Anonymous inner classes are * ignored. * * @return an array of indexes ({@code 0}-based) of all nested classes * in the corresponding class, or an empty array if there are * no nested classes */ int[] getNestedClassIndexes() { int firstIndex = getFirstNestedClassIndex(); if (firstIndex == -1) { return EMPTY_INT_ARRAY; } assert signatures.get(firstIndex).charAt(0) == '['; final int size = size(); if (firstIndex == (size - 1)) { return new int[] {firstIndex}; } int[] result = null; int count = 1; int startIndex = firstIndex + 1; Iterator it = signatures.subList(startIndex, size).iterator(); for (int index = startIndex; it.hasNext(); index++) { if (it.next().charAt(0) == '[') { if (result == null) { result = new int[size - index + 1]; } result[count++] = index; } } assert (count == 1) == (result == null); if (result == null) { result = new int[1]; } else if (count < result.length) { int[] oldResult = result; result = new int[count]; System.arraycopy(oldResult, 1, result, 1, count - 1); } result[0] = firstIndex; return result; } /** */ int size() { return signatures.size(); } /** */ private void shiftPositions(int fromIndex, int shiftSize) { for (int i = 0; i < positions.length; i++) { int pos = positions[i]; if ((pos != -1) && (pos >= fromIndex)) { positions[i] = pos + shiftSize; } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy