1 package org.junit.runners.parameterized; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Field; 5 import java.util.List; 6 7 import org.junit.runner.notification.RunNotifier; 8 import org.junit.runners.BlockJUnit4ClassRunner; 9 import org.junit.runners.Parameterized.Parameter; 10 import org.junit.runners.model.FrameworkField; 11 import org.junit.runners.model.FrameworkMethod; 12 import org.junit.runners.model.InitializationError; 13 import org.junit.runners.model.Statement; 14 15 /** 16 * A {@link BlockJUnit4ClassRunner} with parameters support. Parameters can be 17 * injected via constructor or into annotated fields. 18 */ 19 public class BlockJUnit4ClassRunnerWithParameters extends 20 BlockJUnit4ClassRunner { 21 private final Object[] parameters; 22 23 private final String name; 24 BlockJUnit4ClassRunnerWithParameters(TestWithParameters test)25 public BlockJUnit4ClassRunnerWithParameters(TestWithParameters test) 26 throws InitializationError { 27 super(test.getTestClass().getJavaClass()); 28 parameters = test.getParameters().toArray( 29 new Object[test.getParameters().size()]); 30 name = test.getName(); 31 } 32 33 @Override createTest()34 public Object createTest() throws Exception { 35 if (fieldsAreAnnotated()) { 36 return createTestUsingFieldInjection(); 37 } else { 38 return createTestUsingConstructorInjection(); 39 } 40 } 41 createTestUsingConstructorInjection()42 private Object createTestUsingConstructorInjection() throws Exception { 43 return getTestClass().getOnlyConstructor().newInstance(parameters); 44 } 45 createTestUsingFieldInjection()46 private Object createTestUsingFieldInjection() throws Exception { 47 List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter(); 48 if (annotatedFieldsByParameter.size() != parameters.length) { 49 throw new Exception( 50 "Wrong number of parameters and @Parameter fields." 51 + " @Parameter fields counted: " 52 + annotatedFieldsByParameter.size() 53 + ", available parameters: " + parameters.length 54 + "."); 55 } 56 Object testClassInstance = getTestClass().getJavaClass().newInstance(); 57 for (FrameworkField each : annotatedFieldsByParameter) { 58 Field field = each.getField(); 59 Parameter annotation = field.getAnnotation(Parameter.class); 60 int index = annotation.value(); 61 try { 62 field.set(testClassInstance, parameters[index]); 63 } catch (IllegalArgumentException iare) { 64 throw new Exception(getTestClass().getName() 65 + ": Trying to set " + field.getName() 66 + " with the value " + parameters[index] 67 + " that is not the right type (" 68 + parameters[index].getClass().getSimpleName() 69 + " instead of " + field.getType().getSimpleName() 70 + ").", iare); 71 } 72 } 73 return testClassInstance; 74 } 75 76 @Override getName()77 protected String getName() { 78 return name; 79 } 80 81 @Override testName(FrameworkMethod method)82 protected String testName(FrameworkMethod method) { 83 return method.getName() + getName(); 84 } 85 86 @Override validateConstructor(List<Throwable> errors)87 protected void validateConstructor(List<Throwable> errors) { 88 validateOnlyOneConstructor(errors); 89 if (fieldsAreAnnotated()) { 90 validateZeroArgConstructor(errors); 91 } 92 } 93 94 @Override validateFields(List<Throwable> errors)95 protected void validateFields(List<Throwable> errors) { 96 super.validateFields(errors); 97 if (fieldsAreAnnotated()) { 98 List<FrameworkField> annotatedFieldsByParameter = getAnnotatedFieldsByParameter(); 99 int[] usedIndices = new int[annotatedFieldsByParameter.size()]; 100 for (FrameworkField each : annotatedFieldsByParameter) { 101 int index = each.getField().getAnnotation(Parameter.class) 102 .value(); 103 if (index < 0 || index > annotatedFieldsByParameter.size() - 1) { 104 errors.add(new Exception("Invalid @Parameter value: " 105 + index + ". @Parameter fields counted: " 106 + annotatedFieldsByParameter.size() 107 + ". Please use an index between 0 and " 108 + (annotatedFieldsByParameter.size() - 1) + ".")); 109 } else { 110 usedIndices[index]++; 111 } 112 } 113 for (int index = 0; index < usedIndices.length; index++) { 114 int numberOfUse = usedIndices[index]; 115 if (numberOfUse == 0) { 116 errors.add(new Exception("@Parameter(" + index 117 + ") is never used.")); 118 } else if (numberOfUse > 1) { 119 errors.add(new Exception("@Parameter(" + index 120 + ") is used more than once (" + numberOfUse + ").")); 121 } 122 } 123 } 124 } 125 126 @Override classBlock(RunNotifier notifier)127 protected Statement classBlock(RunNotifier notifier) { 128 return childrenInvoker(notifier); 129 } 130 131 @Override getRunnerAnnotations()132 protected Annotation[] getRunnerAnnotations() { 133 return new Annotation[0]; 134 } 135 getAnnotatedFieldsByParameter()136 private List<FrameworkField> getAnnotatedFieldsByParameter() { 137 return getTestClass().getAnnotatedFields(Parameter.class); 138 } 139 fieldsAreAnnotated()140 private boolean fieldsAreAnnotated() { 141 return !getAnnotatedFieldsByParameter().isEmpty(); 142 } 143 } 144