View Javadoc

1   package net.sf.twip.internal;
2   
3   import static org.junit.Assert.assertEquals;
4   
5   import java.lang.reflect.Method;
6   import java.util.*;
7   
8   import net.sf.twip.parameterhandler.ParameterHandler;
9   import net.sf.twip.util.*;
10  
11  import org.junit.runners.model.FrameworkMethod;
12  
13  /**
14   * A {@link FrameworkMethod} that knows about a fixed set of parameters passed into
15   * {@link FrameworkMethod#invokeExplosively(Object, Object...)}
16   */
17  public class FrameworkMethodWithArgs extends FrameworkMethod {
18  
19  	/**
20  	 * @return the list of all permutations of {@link FrameworkMethodWithArgs} that need to be
21  	 *         called for this method.
22  	 */
23  	public static List<FrameworkMethodWithArgs> of(Method method) {
24  		List<FrameworkMethodWithArgs> result = new ArrayList<FrameworkMethodWithArgs>();
25  		result.add(new FrameworkMethodWithArgs(method));
26  		for (final Parameter parameter : ReverseIterable.create(Parameter.of(method))) {
27  			final List<FrameworkMethodWithArgs> next = new ArrayList<FrameworkMethodWithArgs>();
28  			final ParameterHandler parameterHandler = ParameterHandler.of(parameter);
29  			for (final Object value : parameterHandler.getParameterValues()) {
30  				for (final FrameworkMethodWithArgs old : result) {
31  					next.add(new FrameworkMethodWithArgs(old, parameter, value));
32  				}
33  			}
34  			result = next;
35  		}
36  		return result;
37  	}
38  
39  	private final List<Parameter> parameters;
40  	private final List<Object> parameterValues;
41  
42  	/**
43  	 * Constructor that takes a method, defines the description to be its name, and define no
44  	 * parameterValues; you'll have to call the other constructor to derive a new instance with
45  	 * additional parameterValues, or invokeExplosively will fail.
46  	 */
47  	private FrameworkMethodWithArgs(Method method) {
48  		super(method);
49  		this.parameterValues = Collections.emptyList();
50  		this.parameters = Collections.emptyList();
51  	}
52  
53  	/**
54  	 * Copy-Constructor that appends one parameter value.
55  	 */
56  	private FrameworkMethodWithArgs(FrameworkMethodWithArgs old, Parameter parameter,
57  			Object parameterValue) {
58  		super(old.getMethod());
59  
60  		if (!parameter.isCallable(parameterValue))
61  			throw new TwipConfigurationErrorInvalidParameterType(parameter, parameterValue);
62  
63  		this.parameters = new ArrayList<Parameter>(old.parameters);
64  		this.parameters.add(0, parameter);
65  		this.parameterValues = new ArrayList<Object>(old.parameterValues);
66  		this.parameterValues.add(0, parameterValue);
67  	}
68  
69  	@Override
70  	public Object invokeExplosively(Object target, Object... parameterValues) throws Throwable {
71  		assertEquals("don't call this with parameters; I know them already!",
72  				parameterValues.length, 0);
73  		assertEquals("you didn't specify all parameters for the method", getMethod()
74  				.getParameterTypes().length, this.parameterValues.size());
75  		return super.invokeExplosively(target, this.parameterValues.toArray());
76  	}
77  
78  	@Override
79  	public String toString() {
80  		StringBuilder out = new StringBuilder();
81  		out.append(getMethod().getName());
82  		out.append("[");
83  		boolean first = true;
84  		for (Object parameterValue : parameterValues) {
85  			if (first)
86  				first = false;
87  			else
88  				out.append(", ");
89  			out.append(toString(parameterValue));
90  		}
91  		out.append("]");
92  		return out.toString();
93  	}
94  
95  	/**
96  	 * @return the toString() of a parameter suitable as a method name suffix, i.e. with returns and
97  	 *         unicode characters replaced by harmless escape sequences.
98  	 */
99  	private String toString(Object parameterValue) {
100 		final StringBuilder out = new StringBuilder();
101 		for (final char c : String.valueOf(parameterValue).toCharArray()) {
102 			switch (c) {
103 			case '\n':
104 				out.append("\\n");
105 				break;
106 			case '\r':
107 				out.append("\\r");
108 				break;
109 			case '\t':
110 				out.append("\\t");
111 				break;
112 			case '(':
113 				out.append("[");
114 				break;
115 			case ')':
116 				out.append("]");
117 				break;
118 			default:
119 				if (c > 256) {
120 					out.append("\\u");
121 					out.append(String.format("%04X", Integer.valueOf(c)));
122 				} else {
123 					out.append(c);
124 				}
125 			}
126 		}
127 		return out.toString();
128 	}
129 }