1/**
2 *
3 */
4package org.junit.experimental.theories.internal;
5
6import java.lang.reflect.Method;
7import java.util.ArrayList;
8import java.util.List;
9
10import org.junit.experimental.theories.ParameterSignature;
11import org.junit.experimental.theories.ParameterSupplier;
12import org.junit.experimental.theories.ParametersSuppliedBy;
13import org.junit.experimental.theories.PotentialAssignment;
14import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException;
15import org.junit.runners.model.TestClass;
16
17/**
18 * A potentially incomplete list of value assignments for a method's formal
19 * parameters
20 */
21public class Assignments {
22	private List<PotentialAssignment> fAssigned;
23
24	private final List<ParameterSignature> fUnassigned;
25
26	private final TestClass fClass;
27
28	private Assignments(List<PotentialAssignment> assigned,
29			List<ParameterSignature> unassigned, TestClass testClass) {
30		fUnassigned= unassigned;
31		fAssigned= assigned;
32		fClass= testClass;
33	}
34
35	/**
36	 * Returns a new assignment list for {@code testMethod}, with no params
37	 * assigned.
38	 */
39	public static Assignments allUnassigned(Method testMethod,
40			TestClass testClass) throws Exception {
41		List<ParameterSignature> signatures;
42		signatures= ParameterSignature.signatures(testClass
43				.getOnlyConstructor());
44		signatures.addAll(ParameterSignature.signatures(testMethod));
45		return new Assignments(new ArrayList<PotentialAssignment>(),
46				signatures, testClass);
47	}
48
49	public boolean isComplete() {
50		return fUnassigned.size() == 0;
51	}
52
53	public ParameterSignature nextUnassigned() {
54		return fUnassigned.get(0);
55	}
56
57	public Assignments assignNext(PotentialAssignment source) {
58		List<PotentialAssignment> assigned= new ArrayList<PotentialAssignment>(
59				fAssigned);
60		assigned.add(source);
61
62		return new Assignments(assigned, fUnassigned.subList(1, fUnassigned
63				.size()), fClass);
64	}
65
66	public Object[] getActualValues(int start, int stop, boolean nullsOk)
67			throws CouldNotGenerateValueException {
68		Object[] values= new Object[stop - start];
69		for (int i= start; i < stop; i++) {
70			Object value= fAssigned.get(i).getValue();
71			if (value == null && !nullsOk)
72				throw new CouldNotGenerateValueException();
73			values[i - start]= value;
74		}
75		return values;
76	}
77
78	public List<PotentialAssignment> potentialsForNextUnassigned()
79			throws InstantiationException, IllegalAccessException {
80		ParameterSignature unassigned= nextUnassigned();
81		return getSupplier(unassigned).getValueSources(unassigned);
82	}
83
84	public ParameterSupplier getSupplier(ParameterSignature unassigned)
85			throws InstantiationException, IllegalAccessException {
86		ParameterSupplier supplier= getAnnotatedSupplier(unassigned);
87		if (supplier != null)
88			return supplier;
89
90		return new AllMembersSupplier(fClass);
91	}
92
93	public ParameterSupplier getAnnotatedSupplier(ParameterSignature unassigned)
94			throws InstantiationException, IllegalAccessException {
95		ParametersSuppliedBy annotation= unassigned
96				.findDeepAnnotation(ParametersSuppliedBy.class);
97		if (annotation == null)
98			return null;
99		return annotation.value().newInstance();
100	}
101
102	public Object[] getConstructorArguments(boolean nullsOk)
103			throws CouldNotGenerateValueException {
104		return getActualValues(0, getConstructorParameterCount(), nullsOk);
105	}
106
107	public Object[] getMethodArguments(boolean nullsOk)
108			throws CouldNotGenerateValueException {
109		return getActualValues(getConstructorParameterCount(),
110				fAssigned.size(), nullsOk);
111	}
112
113	public Object[] getAllArguments(boolean nullsOk)
114			throws CouldNotGenerateValueException {
115		return getActualValues(0, fAssigned.size(), nullsOk);
116	}
117
118	private int getConstructorParameterCount() {
119		List<ParameterSignature> signatures= ParameterSignature
120				.signatures(fClass.getOnlyConstructor());
121		int constructorParameterCount= signatures.size();
122		return constructorParameterCount;
123	}
124
125	public Object[] getArgumentStrings(boolean nullsOk)
126			throws CouldNotGenerateValueException {
127		Object[] values= new Object[fAssigned.size()];
128		for (int i= 0; i < values.length; i++) {
129			values[i]= fAssigned.get(i).getDescription();
130		}
131		return values;
132	}
133}