/*
* Copyright 2011 the original author or authors.
*
* Licensed 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.powermock.tests.utils.impl;
import org.powermock.core.IndicateReloadClass;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
import org.powermock.tests.utils.TestClassesExtractor;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Implementation of the {@link TestClassesExtractor} interface that extract
* classes from the {@link PrepareForTest} or {@link PrepareOnlyThisForTest}
* annotations. It also adds the test case to the array of classes that should
* be modified.
*
*/
public class PrepareForTestExtractorImpl extends AbstractTestClassExtractor {
public PrepareForTestExtractorImpl(){
this(false);
}
public PrepareForTestExtractorImpl(boolean includeMethods) {
super(includeMethods);
}
/**
* {@inheritDoc}
*/
@Override
protected String[] getClassesToModify(AnnotatedElement element) {
Set<String> all = new LinkedHashSet<String>();
addTestCase(all, element);
PrepareForTest prepareForTestAnnotation = element.getAnnotation(PrepareForTest.class);
PrepareOnlyThisForTest prepareOnlyThisForTestAnnotation = element.getAnnotation(PrepareOnlyThisForTest.class);
final boolean prepareForTestAnnotationPresent = prepareForTestAnnotation != null;
final boolean prepareOnlyThisForTestAnnotationPresent = prepareOnlyThisForTestAnnotation != null;
if (!prepareForTestAnnotationPresent && !prepareOnlyThisForTestAnnotationPresent) {
return null;
}
if (prepareForTestAnnotationPresent) {
final Class<?>[] classesToMock = prepareForTestAnnotation.value();
for (Class<?> classToMock : classesToMock) {
if (!classToMock.equals(IndicateReloadClass.class)) {
addClassHierarchy(all, classToMock);
}
}
addFullyQualifiedNames(all, prepareForTestAnnotation);
}
if (prepareOnlyThisForTestAnnotationPresent) {
final Class<?>[] classesToMock = prepareOnlyThisForTestAnnotation.value();
for (Class<?> classToMock : classesToMock) {
if (!classToMock.equals(IndicateReloadClass.class)) {
all.add(classToMock.getName());
}
}
addFullyQualifiedNames(all, prepareOnlyThisForTestAnnotation);
}
return all.toArray(new String[all.size()]);
}
private void addTestCase(Set<String> all, AnnotatedElement element) {
Class<?> testClass = null;
if (element instanceof Class<?>) {
testClass = (Class<?>) element;
} else if (element instanceof Method) {
testClass = ((Method) element).getDeclaringClass();
}
addClassHierarchy(all, testClass);
}
private void addFullyQualifiedNames(Set<String> all, PrepareForTest annotation) {
String[] fullyQualifiedNames = annotation.fullyQualifiedNames();
addFullyQualifiedNames(all, fullyQualifiedNames);
}
private void addFullyQualifiedNames(Set<String> all, PrepareOnlyThisForTest annotation) {
String[] fullyQualifiedNames = annotation.fullyQualifiedNames();
addFullyQualifiedNames(all, fullyQualifiedNames);
}
private void addFullyQualifiedNames(Set<String> all, String[] fullyQualifiedNames) {
for (String string : fullyQualifiedNames) {
if (!"".equals(string)) {
all.add(string);
}
}
}
private void addClassHierarchy(Set<String> all, Class<?> classToMock) {
while (classToMock != null && !classToMock.equals(Object.class)) {
addInnerClassesAndInterfaces(all, classToMock);
all.add(classToMock.getName());
classToMock = classToMock.getSuperclass();
}
}
private void addInnerClassesAndInterfaces(Set<String> all, Class<?> classToMock) {
Class<?>[] declaredClasses = classToMock.getDeclaredClasses();
for (Class<?> innerClass : declaredClasses) {
all.add(innerClass.getName());
}
}
}