| package org.junit.experimental.theories.internal; |
| |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Field; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.junit.Assume; |
| import org.junit.experimental.theories.DataPoint; |
| import org.junit.experimental.theories.DataPoints; |
| import org.junit.experimental.theories.ParameterSignature; |
| import org.junit.experimental.theories.ParameterSupplier; |
| import org.junit.experimental.theories.PotentialAssignment; |
| import org.junit.runners.model.FrameworkField; |
| import org.junit.runners.model.FrameworkMethod; |
| import org.junit.runners.model.TestClass; |
| |
| /** |
| * Supplies Theory parameters based on all public members of the target class. |
| */ |
| public class AllMembersSupplier extends ParameterSupplier { |
| static class MethodParameterValue extends PotentialAssignment { |
| private final FrameworkMethod method; |
| |
| private MethodParameterValue(FrameworkMethod dataPointMethod) { |
| method = dataPointMethod; |
| } |
| |
| @Override |
| public Object getValue() throws CouldNotGenerateValueException { |
| try { |
| return method.invokeExplosively(null); |
| } catch (IllegalArgumentException e) { |
| throw new RuntimeException( |
| "unexpected: argument length is checked"); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException( |
| "unexpected: getMethods returned an inaccessible method"); |
| } catch (Throwable throwable) { |
| DataPoint annotation = method.getAnnotation(DataPoint.class); |
| Assume.assumeTrue(annotation == null || !isAssignableToAnyOf(annotation.ignoredExceptions(), throwable)); |
| |
| throw new CouldNotGenerateValueException(throwable); |
| } |
| } |
| |
| @Override |
| public String getDescription() throws CouldNotGenerateValueException { |
| return method.getName(); |
| } |
| } |
| |
| private final TestClass clazz; |
| |
| /** |
| * Constructs a new supplier for {@code type} |
| */ |
| public AllMembersSupplier(TestClass type) { |
| clazz = type; |
| } |
| |
| @Override |
| public List<PotentialAssignment> getValueSources(ParameterSignature sig) throws Throwable { |
| List<PotentialAssignment> list = new ArrayList<PotentialAssignment>(); |
| |
| addSinglePointFields(sig, list); |
| addMultiPointFields(sig, list); |
| addSinglePointMethods(sig, list); |
| addMultiPointMethods(sig, list); |
| |
| return list; |
| } |
| |
| private void addMultiPointMethods(ParameterSignature sig, List<PotentialAssignment> list) throws Throwable { |
| for (FrameworkMethod dataPointsMethod : getDataPointsMethods(sig)) { |
| Class<?> returnType = dataPointsMethod.getReturnType(); |
| |
| if ((returnType.isArray() && sig.canPotentiallyAcceptType(returnType.getComponentType())) || |
| Iterable.class.isAssignableFrom(returnType)) { |
| try { |
| addDataPointsValues(returnType, sig, dataPointsMethod.getName(), list, |
| dataPointsMethod.invokeExplosively(null)); |
| } catch (Throwable throwable) { |
| DataPoints annotation = dataPointsMethod.getAnnotation(DataPoints.class); |
| if (annotation != null && isAssignableToAnyOf(annotation.ignoredExceptions(), throwable)) { |
| return; |
| } else { |
| throw throwable; |
| } |
| } |
| } |
| } |
| } |
| |
| private void addSinglePointMethods(ParameterSignature sig, List<PotentialAssignment> list) { |
| for (FrameworkMethod dataPointMethod : getSingleDataPointMethods(sig)) { |
| if (sig.canAcceptType(dataPointMethod.getType())) { |
| list.add(new MethodParameterValue(dataPointMethod)); |
| } |
| } |
| } |
| |
| private void addMultiPointFields(ParameterSignature sig, List<PotentialAssignment> list) { |
| for (final Field field : getDataPointsFields(sig)) { |
| Class<?> type = field.getType(); |
| addDataPointsValues(type, sig, field.getName(), list, getStaticFieldValue(field)); |
| } |
| } |
| |
| private void addSinglePointFields(ParameterSignature sig, List<PotentialAssignment> list) { |
| for (final Field field : getSingleDataPointFields(sig)) { |
| Object value = getStaticFieldValue(field); |
| |
| if (sig.canAcceptValue(value)) { |
| list.add(PotentialAssignment.forValue(field.getName(), value)); |
| } |
| } |
| } |
| |
| private void addDataPointsValues(Class<?> type, ParameterSignature sig, String name, |
| List<PotentialAssignment> list, Object value) { |
| if (type.isArray()) { |
| addArrayValues(sig, name, list, value); |
| } |
| else if (Iterable.class.isAssignableFrom(type)) { |
| addIterableValues(sig, name, list, (Iterable<?>) value); |
| } |
| } |
| |
| private void addArrayValues(ParameterSignature sig, String name, List<PotentialAssignment> list, Object array) { |
| for (int i = 0; i < Array.getLength(array); i++) { |
| Object value = Array.get(array, i); |
| if (sig.canAcceptValue(value)) { |
| list.add(PotentialAssignment.forValue(name + "[" + i + "]", value)); |
| } |
| } |
| } |
| |
| private void addIterableValues(ParameterSignature sig, String name, List<PotentialAssignment> list, Iterable<?> iterable) { |
| Iterator<?> iterator = iterable.iterator(); |
| int i = 0; |
| while (iterator.hasNext()) { |
| Object value = iterator.next(); |
| if (sig.canAcceptValue(value)) { |
| list.add(PotentialAssignment.forValue(name + "[" + i + "]", value)); |
| } |
| i += 1; |
| } |
| } |
| |
| private Object getStaticFieldValue(final Field field) { |
| try { |
| return field.get(null); |
| } catch (IllegalArgumentException e) { |
| throw new RuntimeException( |
| "unexpected: field from getClass doesn't exist on object"); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException( |
| "unexpected: getFields returned an inaccessible field"); |
| } |
| } |
| |
| private static boolean isAssignableToAnyOf(Class<?>[] typeArray, Object target) { |
| for (Class<?> type : typeArray) { |
| if (type.isAssignableFrom(target.getClass())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected Collection<FrameworkMethod> getDataPointsMethods(ParameterSignature sig) { |
| return clazz.getAnnotatedMethods(DataPoints.class); |
| } |
| |
| protected Collection<Field> getSingleDataPointFields(ParameterSignature sig) { |
| List<FrameworkField> fields = clazz.getAnnotatedFields(DataPoint.class); |
| Collection<Field> validFields = new ArrayList<Field>(); |
| |
| for (FrameworkField frameworkField : fields) { |
| validFields.add(frameworkField.getField()); |
| } |
| |
| return validFields; |
| } |
| |
| protected Collection<Field> getDataPointsFields(ParameterSignature sig) { |
| List<FrameworkField> fields = clazz.getAnnotatedFields(DataPoints.class); |
| Collection<Field> validFields = new ArrayList<Field>(); |
| |
| for (FrameworkField frameworkField : fields) { |
| validFields.add(frameworkField.getField()); |
| } |
| |
| return validFields; |
| } |
| |
| protected Collection<FrameworkMethod> getSingleDataPointMethods(ParameterSignature sig) { |
| return clazz.getAnnotatedMethods(DataPoint.class); |
| } |
| |
| } |