forked from grpc/grpc-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathForwardingTestUtil.java
More file actions
138 lines (130 loc) · 5.31 KB
/
ForwardingTestUtil.java
File metadata and controls
138 lines (130 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* Copyright 2017 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc;
import static junit.framework.TestCase.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.verify;
import com.google.common.base.Defaults;
import com.google.common.base.MoreObjects;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import javax.annotation.Nullable;
/**
* A util class to help test forwarding classes.
*/
public final class ForwardingTestUtil {
/**
* Use reflection to perform a basic sanity test. The forwarding class should forward all public
* methods to the delegate, except for those in skippedMethods. This does NOT verify that
* arguments or return values are forwarded properly.
*
* @param delegateClass The class whose methods should be forwarded.
* @param mockDelegate The mockito mock of the delegate class.
* @param forwarder The forwarder object that forwards to the mockDelegate.
* @param skippedMethods A collection of methods that are skipped by the test.
*/
public static <T> void testMethodsForwarded(
Class<T> delegateClass,
T mockDelegate,
T forwarder,
Collection<Method> skippedMethods) throws Exception {
testMethodsForwarded(
delegateClass, mockDelegate, forwarder, skippedMethods,
new ArgumentProvider() {
@Override
public Object get(Method method, int argPos, Class<?> clazz) {
return null;
}
});
}
/**
* Use reflection to perform a basic sanity test. The forwarding class should forward all public
* methods to the delegate, except for those in skippedMethods. This does NOT verify that return
* values are forwarded properly, and can only verify the propagation of arguments for which
* {@code argProvider} returns distinctive non-null values.
*
* @param delegateClass The class whose methods should be forwarded.
* @param mockDelegate The mockito mock of the delegate class.
* @param forwarder The forwarder object that forwards to the mockDelegate.
* @param skippedMethods A collection of methods that are skipped by the test.
* @param argProvider provides argument to be passed to tested forwarding methods.
*/
public static <T> void testMethodsForwarded(
Class<T> delegateClass,
T mockDelegate,
T forwarder,
Collection<Method> skippedMethods,
ArgumentProvider argProvider) throws Exception {
assertTrue(mockingDetails(mockDelegate).isMock());
assertFalse(mockingDetails(forwarder).isMock());
for (Method method : delegateClass.getDeclaredMethods()) {
if (Modifier.isStatic(method.getModifiers())
|| Modifier.isPrivate(method.getModifiers())
|| Modifier.isFinal(method.getModifiers())
|| skippedMethods.contains(method)) {
continue;
}
Class<?>[] argTypes = method.getParameterTypes();
Object[] args = new Object[argTypes.length];
for (int i = 0; i < argTypes.length; i++) {
if ((args[i] = argProvider.get(method, i, argTypes[i])) == null) {
args[i] = Defaults.defaultValue(argTypes[i]);
}
}
method.invoke(forwarder, args);
try {
method.invoke(verify(mockDelegate), args);
} catch (InvocationTargetException e) {
AssertionError ae =
new AssertionError(String.format("Method was not forwarded: %s", method));
ae.initCause(e);
throw ae;
}
}
boolean skipToString = false;
for (Method method : skippedMethods) {
if (method.getName().equals("toString")) {
skipToString = true;
break;
}
}
if (!skipToString) {
String actual = forwarder.toString();
String expected =
MoreObjects.toStringHelper(forwarder).add("delegate", mockDelegate).toString();
assertEquals("Method toString() was not forwarded properly", expected, actual);
}
}
/**
* Provides arguments for forwarded methods tested in {@link #testMethodsForwarded}.
*/
public interface ArgumentProvider {
/**
* Return an instance of the given class to be used as an argument passed to one method call.
* If one method has multiple arguments with the same type, each occurrence will call this
* method once. It is recommended that each invocation returns a distinctive object for the
* same type, in order to verify that arguments are passed by the tested class correctly.
*
* @return a value to be passed as an argument. If {@code null}, {@link Defaults#defaultValue}
* will be used.
*/
@Nullable Object get(Method method, int argPos, Class<?> clazz);
}
}