package org.testng.internal;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.testng.IInstanceInfo;
import org.testng.IObjectFactory;
import org.testng.IObjectFactory2;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestObjectFactory;
import org.testng.TestNGException;
import org.testng.annotations.IFactoryAnnotation;
import org.testng.collections.Lists;
import org.testng.collections.Maps;
import org.testng.internal.annotations.IAnnotationFinder;
import org.testng.xml.XmlTest;
/**
* This class represents a method annotated with @Factory
*/
public class FactoryMethod extends BaseTestMethod {
private static final long serialVersionUID = -7329918821346197099L;
private final IFactoryAnnotation factoryAnnotation;
private final Object m_instance;
private final XmlTest m_xmlTest;
private final ITestContext m_testContext;
private final ITestObjectFactory objectFactory;
public FactoryMethod(ConstructorOrMethod com, Object instance, XmlTest xmlTest, IAnnotationFinder annotationFinder,
ITestContext testContext, ITestObjectFactory objectFactory) {
super(com.getName(), com, annotationFinder, instance);
Utils.checkInstanceOrStatic(instance, com.getMethod());
Utils.checkReturnType(com.getMethod(), Object[].class, IInstanceInfo[].class);
Class<?> declaringClass = com.getDeclaringClass();
if (instance != null && ! declaringClass.isAssignableFrom(instance.getClass())) {
throw new TestNGException("Mismatch between instance/method classes:"
+ instance.getClass() + " " + declaringClass);
}
if (instance == null && com.getMethod() != null && !Modifier.isStatic(com.getMethod().getModifiers())) {
throw new TestNGException("An inner factory method MUST be static. But '" + com.getMethod().getName() + "' from '" + declaringClass.getName() + "' is not.");
}
if (com.getMethod() != null && !Modifier.isPublic(com.getMethod().getModifiers())) {
try {
com.getMethod().setAccessible(true);
} catch (SecurityException e) {
throw new TestNGException(com.getMethod().getName() + " must be public", e);
}
}
factoryAnnotation = annotationFinder.findAnnotation(com, IFactoryAnnotation.class);
m_instance = instance;
m_xmlTest = xmlTest;
m_testContext = testContext;
NoOpTestClass tc = new NoOpTestClass();
tc.setTestClass(declaringClass);
m_testClass = tc;
this.objectFactory = objectFactory;
}
public Object[] invoke() {
List<Object> result = Lists.newArrayList();
Map<String, String> allParameterNames = Maps.newHashMap();
Iterator<Object[]> parameterIterator =
Parameters.handleParameters(this,
allParameterNames,
m_instance,
new Parameters.MethodParameters(m_xmlTest.getAllParameters(),
findMethodParameters(m_xmlTest),
null, null, m_testContext,
null /* testResult */),
m_xmlTest.getSuite(),
m_annotationFinder,
null /* fedInstance */).parameters;
try {
List<Integer> indices = factoryAnnotation.getIndices();
int position = 0;
while (parameterIterator.hasNext()) {
Object[] parameters = parameterIterator.next();
ConstructorOrMethod com = getConstructorOrMethod();
if (com.getMethod() != null) {
Object[] testInstances = (Object[]) com.getMethod().invoke(m_instance, parameters);
if (indices == null || indices.isEmpty()) {
for (Object testInstance : testInstances) {
result.add(testInstance);
}
} else {
for (Integer index : indices) {
int i = index - position;
if (i >= 0 && i < testInstances.length) {
result.add(testInstances[i]);
}
}
}
position += testInstances.length;
} else {
if (indices == null || indices.isEmpty() || indices.contains(position)) {
Object instance;
if (objectFactory instanceof IObjectFactory) {
instance = ((IObjectFactory) objectFactory).newInstance(com.getConstructor(), parameters);
} else if (objectFactory instanceof IObjectFactory2) {
instance = ((IObjectFactory2) objectFactory).newInstance(com.getDeclaringClass());
} else {
throw new IllegalStateException("Unsupported ITestObjectFactory " + objectFactory.getClass());
}
result.add(instance);
}
position++;
}
}
} catch (Throwable t) {
ConstructorOrMethod com = getConstructorOrMethod();
throw new TestNGException("The factory method "
+ com.getDeclaringClass() + "." + com.getName()
+ "() threw an exception", t);
}
return result.toArray(new Object[result.size()]);
}
@Override
public ITestNGMethod clone() {
throw new IllegalStateException("clone is not supported for FactoryMethod");
}
}