• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *
3  */
4 package org.junit.experimental.theories;
5 
6 import java.lang.reflect.Field;
7 import java.lang.reflect.InvocationTargetException;
8 import java.lang.reflect.Modifier;
9 import java.util.ArrayList;
10 import java.util.List;
11 
12 import org.junit.Assert;
13 import org.junit.experimental.theories.PotentialAssignment.CouldNotGenerateValueException;
14 import org.junit.experimental.theories.internal.Assignments;
15 import org.junit.experimental.theories.internal.ParameterizedAssertionError;
16 import org.junit.internal.AssumptionViolatedException;
17 import org.junit.runners.BlockJUnit4ClassRunner;
18 import org.junit.runners.model.FrameworkMethod;
19 import org.junit.runners.model.InitializationError;
20 import org.junit.runners.model.Statement;
21 import org.junit.runners.model.TestClass;
22 
23 public class Theories extends BlockJUnit4ClassRunner {
Theories(Class<?> klass)24 	public Theories(Class<?> klass) throws InitializationError {
25 		super(klass);
26 	}
27 
28 	@Override
collectInitializationErrors(List<Throwable> errors)29 	protected void collectInitializationErrors(List<Throwable> errors) {
30 		super.collectInitializationErrors(errors);
31 		validateDataPointFields(errors);
32 	}
33 
validateDataPointFields(List<Throwable> errors)34 	private void validateDataPointFields(List<Throwable> errors) {
35 		Field[] fields= getTestClass().getJavaClass().getDeclaredFields();
36 
37 		for (Field each : fields)
38 			if (each.getAnnotation(DataPoint.class) != null && !Modifier.isStatic(each.getModifiers()))
39 				errors.add(new Error("DataPoint field " + each.getName() + " must be static"));
40 	}
41 
42 	@Override
validateConstructor(List<Throwable> errors)43 	protected void validateConstructor(List<Throwable> errors) {
44 		validateOnlyOneConstructor(errors);
45 	}
46 
47 	@Override
validateTestMethods(List<Throwable> errors)48 	protected void validateTestMethods(List<Throwable> errors) {
49 		for (FrameworkMethod each : computeTestMethods())
50 			if(each.getAnnotation(Theory.class) != null)
51 				each.validatePublicVoid(false, errors);
52 			else
53 				each.validatePublicVoidNoArg(false, errors);
54 	}
55 
56 	@Override
computeTestMethods()57 	protected List<FrameworkMethod> computeTestMethods() {
58 		List<FrameworkMethod> testMethods= super.computeTestMethods();
59 		List<FrameworkMethod> theoryMethods= getTestClass().getAnnotatedMethods(Theory.class);
60 		testMethods.removeAll(theoryMethods);
61 		testMethods.addAll(theoryMethods);
62 		return testMethods;
63 	}
64 
65 	@Override
methodBlock(final FrameworkMethod method)66 	public Statement methodBlock(final FrameworkMethod method) {
67 		return new TheoryAnchor(method, getTestClass());
68 	}
69 
70 	public static class TheoryAnchor extends Statement {
71 		private int successes= 0;
72 
73 		private FrameworkMethod fTestMethod;
74         private TestClass fTestClass;
75 
76 		private List<AssumptionViolatedException> fInvalidParameters= new ArrayList<AssumptionViolatedException>();
77 
TheoryAnchor(FrameworkMethod method, TestClass testClass)78 		public TheoryAnchor(FrameworkMethod method, TestClass testClass) {
79 			fTestMethod= method;
80             fTestClass= testClass;
81 		}
82 
getTestClass()83         private TestClass getTestClass() {
84             return fTestClass;
85         }
86 
87 		@Override
evaluate()88 		public void evaluate() throws Throwable {
89 			runWithAssignment(Assignments.allUnassigned(
90 					fTestMethod.getMethod(), getTestClass()));
91 
92 			if (successes == 0)
93 				Assert
94 						.fail("Never found parameters that satisfied method assumptions.  Violated assumptions: "
95 								+ fInvalidParameters);
96 		}
97 
runWithAssignment(Assignments parameterAssignment)98 		protected void runWithAssignment(Assignments parameterAssignment)
99 				throws Throwable {
100 			if (!parameterAssignment.isComplete()) {
101 				runWithIncompleteAssignment(parameterAssignment);
102 			} else {
103 				runWithCompleteAssignment(parameterAssignment);
104 			}
105 		}
106 
runWithIncompleteAssignment(Assignments incomplete)107 		protected void runWithIncompleteAssignment(Assignments incomplete)
108 				throws InstantiationException, IllegalAccessException,
109 				Throwable {
110 			for (PotentialAssignment source : incomplete
111 					.potentialsForNextUnassigned()) {
112 				runWithAssignment(incomplete.assignNext(source));
113 			}
114 		}
115 
runWithCompleteAssignment(final Assignments complete)116 		protected void runWithCompleteAssignment(final Assignments complete)
117 				throws InstantiationException, IllegalAccessException,
118 				InvocationTargetException, NoSuchMethodException, Throwable {
119 			new BlockJUnit4ClassRunner(getTestClass().getJavaClass()) {
120 				@Override
121 				protected void collectInitializationErrors(
122 						List<Throwable> errors) {
123 					// do nothing
124 				}
125 
126 				@Override
127 				public Statement methodBlock(FrameworkMethod method) {
128 					final Statement statement= super.methodBlock(method);
129 					return new Statement() {
130 						@Override
131 						public void evaluate() throws Throwable {
132 							try {
133 								statement.evaluate();
134 								handleDataPointSuccess();
135 							} catch (AssumptionViolatedException e) {
136 								handleAssumptionViolation(e);
137 							} catch (Throwable e) {
138 								reportParameterizedError(e, complete
139 										.getArgumentStrings(nullsOk()));
140 							}
141 						}
142 
143 					};
144 				}
145 
146 				@Override
147 				protected Statement methodInvoker(FrameworkMethod method, Object test) {
148 					return methodCompletesWithParameters(method, complete, test);
149 				}
150 
151 				@Override
152 				public Object createTest() throws Exception {
153 					return getTestClass().getOnlyConstructor().newInstance(
154 							complete.getConstructorArguments(nullsOk()));
155 				}
156 			}.methodBlock(fTestMethod).evaluate();
157 		}
158 
159 		private Statement methodCompletesWithParameters(
160 				final FrameworkMethod method, final Assignments complete, final Object freshInstance) {
161 			return new Statement() {
162 				@Override
163 				public void evaluate() throws Throwable {
164 					try {
165 						final Object[] values= complete.getMethodArguments(
166 								nullsOk());
167 						method.invokeExplosively(freshInstance, values);
168 					} catch (CouldNotGenerateValueException e) {
169 						// ignore
170 					}
171 				}
172 			};
173 		}
174 
175 		protected void handleAssumptionViolation(AssumptionViolatedException e) {
176 			fInvalidParameters.add(e);
177 		}
178 
179 		protected void reportParameterizedError(Throwable e, Object... params)
180 				throws Throwable {
181 			if (params.length == 0)
182 				throw e;
183 			throw new ParameterizedAssertionError(e, fTestMethod.getName(),
184 					params);
185 		}
186 
187 		private boolean nullsOk() {
188 			Theory annotation= fTestMethod.getMethod().getAnnotation(
189 					Theory.class);
190 			if (annotation == null)
191 				return false;
192 			return annotation.nullsAccepted();
193 		}
194 
195 		protected void handleDataPointSuccess() {
196 			successes++;
197 		}
198 	}
199 }
200