1b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/**
2b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot *
3b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */
4b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpackage org.junit.experimental.theories.internal;
5b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
6b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Array;
7b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Field;
8b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.lang.reflect.Modifier;
9b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.ArrayList;
10b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport java.util.List;
11b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
12b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.experimental.theories.DataPoint;
13b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.experimental.theories.DataPoints;
14b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.experimental.theories.ParameterSignature;
15b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.experimental.theories.ParameterSupplier;
16b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.experimental.theories.PotentialAssignment;
17b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runners.model.FrameworkMethod;
18b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotimport org.junit.runners.model.TestClass;
19b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
20b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot/**
21b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot * Supplies Theory parameters based on all public members of the target class.
22b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot */
23b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabotpublic class AllMembersSupplier extends ParameterSupplier {
24b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	static class MethodParameterValue extends PotentialAssignment {
25b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		private final FrameworkMethod fMethod;
26b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
27b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		private MethodParameterValue(FrameworkMethod dataPointMethod) {
28b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			fMethod= dataPointMethod;
29b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
30b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
31b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		@Override
32b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		public Object getValue() throws CouldNotGenerateValueException {
33b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			try {
34b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				return fMethod.invokeExplosively(null);
35b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			} catch (IllegalArgumentException e) {
36b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				throw new RuntimeException(
37b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot						"unexpected: argument length is checked");
38b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			} catch (IllegalAccessException e) {
39b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				throw new RuntimeException(
40b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot						"unexpected: getMethods returned an inaccessible method");
41b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			} catch (Throwable e) {
42b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				throw new CouldNotGenerateValueException();
43b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				// do nothing, just look for more values
44b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
45b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
46b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
47b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		@Override
48b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		public String getDescription() throws CouldNotGenerateValueException {
49b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			return fMethod.getName();
50b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
51b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
52b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
53b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private final TestClass fClass;
54b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
55b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	/**
56b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 * Constructs a new supplier for {@code type}
57b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	 */
58b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public AllMembersSupplier(TestClass type) {
59b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		fClass= type;
60b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
61b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
62b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	@Override
63b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
64b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		List<PotentialAssignment> list= new ArrayList<PotentialAssignment>();
65b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
66b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		addFields(sig, list);
67b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		addSinglePointMethods(sig, list);
68b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		addMultiPointMethods(list);
69b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
70b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		return list;
71b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
72b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
73b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private void addMultiPointMethods(List<PotentialAssignment> list) {
74b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (FrameworkMethod dataPointsMethod : fClass
75b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				.getAnnotatedMethods(DataPoints.class))
76b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			try {
77b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				addArrayValues(dataPointsMethod.getName(), list, dataPointsMethod.invokeExplosively(null));
78b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			} catch (Throwable e) {
79b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				// ignore and move on
80b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
81b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
82b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
83b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	@SuppressWarnings("deprecation")
84b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private void addSinglePointMethods(ParameterSignature sig,
85b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			List<PotentialAssignment> list) {
86b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (FrameworkMethod dataPointMethod : fClass
87b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				.getAnnotatedMethods(DataPoint.class)) {
88b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			Class<?> type= sig.getType();
89b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if ((dataPointMethod.producesType(type)))
90b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				list.add(new MethodParameterValue(dataPointMethod));
91b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
92b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
93b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
94b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private void addFields(ParameterSignature sig,
95b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			List<PotentialAssignment> list) {
96b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (final Field field : fClass.getJavaClass().getFields()) {
97b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			if (Modifier.isStatic(field.getModifiers())) {
98b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				Class<?> type= field.getType();
99b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				if (sig.canAcceptArrayType(type)
100b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot						&& field.getAnnotation(DataPoints.class) != null) {
101b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					addArrayValues(field.getName(), list, getStaticFieldValue(field));
102b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				} else if (sig.canAcceptType(type)
103b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot						&& field.getAnnotation(DataPoint.class) != null) {
104b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					list.add(PotentialAssignment
105b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot							.forValue(field.getName(), getStaticFieldValue(field)));
106b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot				}
107b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			}
108b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
109b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
110b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
111b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private void addArrayValues(String name, List<PotentialAssignment> list, Object array) {
112b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		for (int i= 0; i < Array.getLength(array); i++)
113b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			list.add(PotentialAssignment.forValue(name + "[" + i + "]", Array.get(array, i)));
114b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
115b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot
116b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	private Object getStaticFieldValue(final Field field) {
117b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		try {
118b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			return field.get(null);
119b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		} catch (IllegalArgumentException e) {
120b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			throw new RuntimeException(
121b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					"unexpected: field from getClass doesn't exist on object");
122b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		} catch (IllegalAccessException e) {
123b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot			throw new RuntimeException(
124b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot					"unexpected: getFields returned an inaccessible field");
125b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot		}
126b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot	}
127b3823db9f1192d8c81345740b3e65bd6738ba55bBrett Chabot}