blob: 070756192e69a3086e633e5db65bc9aa3584773c [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska24c849c2014-10-27 09:53:05 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska24c849c2014-10-27 09:53:05 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
Pavlin Radoslavovd26f57a2014-10-23 17:19:45 -070016package org.onlab.junit;
Jonathan Hart20d8e512014-10-16 11:05:52 -070017
18import java.lang.reflect.Constructor;
19import java.lang.reflect.Field;
20import java.lang.reflect.InvocationTargetException;
21import java.lang.reflect.Method;
22
23
24/**
25 * Utilities for testing.
26 */
27public final class TestUtils {
28
29 /**
30 * Sets the field, bypassing scope restriction.
31 *
32 * @param subject Object where the field belongs
33 * @param fieldName name of the field to set
34 * @param value value to set to the field.
35 * @param <T> subject type
36 * @param <U> value type
37 * @throws TestUtilsException if there are reflection errors while setting
38 * the field
39 */
40 public static <T, U> void setField(T subject, String fieldName, U value)
41 throws TestUtilsException {
42 @SuppressWarnings("unchecked")
Yuta HIGUCHI6c887d02016-11-21 17:17:13 -080043 Class clazz;
44 if (subject instanceof Class) {
45 // Class was given, assuming intention is to deal with static field
46 clazz = (Class) subject;
47 } else {
48 clazz = subject.getClass();
49 }
Jonathan Hart20d8e512014-10-16 11:05:52 -070050 try {
Ray Milkey5b94aea2015-08-05 11:00:55 -070051 while (clazz != null) {
52 try {
53 Field field = clazz.getDeclaredField(fieldName);
54 field.setAccessible(true);
55 field.set(subject, value);
56 break;
57 } catch (NoSuchFieldException ex) {
58 if (clazz == clazz.getSuperclass()) {
59 break;
60 }
61 clazz = clazz.getSuperclass();
62 }
63 }
64 } catch (SecurityException | IllegalArgumentException |
65 IllegalAccessException e) {
Jonathan Hart20d8e512014-10-16 11:05:52 -070066 throw new TestUtilsException("setField failed", e);
67 }
68 }
69
70 /**
71 * Gets the field, bypassing scope restriction.
72 *
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070073 * @param subject Object where the field belongs
Jonathan Hart20d8e512014-10-16 11:05:52 -070074 * @param fieldName name of the field to get
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070075 * @param <T> subject type
76 * @param <U> fieldO value type
Jonathan Hart20d8e512014-10-16 11:05:52 -070077 * @return value of the field.
Jonathan Hart20d8e512014-10-16 11:05:52 -070078 * @throws TestUtilsException if there are reflection errors while getting
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070079 * the field
Jonathan Hart20d8e512014-10-16 11:05:52 -070080 */
81 public static <T, U> U getField(T subject, String fieldName)
82 throws TestUtilsException {
83 try {
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070084 NoSuchFieldException exception = null;
Jonathan Hart20d8e512014-10-16 11:05:52 -070085 @SuppressWarnings("unchecked")
Yuta HIGUCHI6c887d02016-11-21 17:17:13 -080086 Class clazz;
87 if (subject instanceof Class) {
88 // Class was given, assuming intention is to deal with static field
89 clazz = (Class) subject;
90 } else {
91 clazz = subject.getClass();
92 }
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070093 while (clazz != null) {
94 try {
95 Field field = clazz.getDeclaredField(fieldName);
96 field.setAccessible(true);
Jonathan Hart20d8e512014-10-16 11:05:52 -070097
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070098 @SuppressWarnings("unchecked")
99 U result = (U) field.get(subject);
100 return result;
101 } catch (NoSuchFieldException e) {
102 exception = e;
103 if (clazz == clazz.getSuperclass()) {
104 break;
105 }
106 clazz = clazz.getSuperclass();
107 }
108 }
109 throw new TestUtilsException("Field not found. " + fieldName, exception);
110
111 } catch (SecurityException |
112 IllegalArgumentException | IllegalAccessException e) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700113 throw new TestUtilsException("getField failed", e);
114 }
115 }
116
117 /**
118 * Calls the method, bypassing scope restriction.
119 *
120 * @param subject Object where the method belongs
121 * @param methodName name of the method to call
122 * @param paramTypes formal parameter type array
123 * @param args arguments
124 * @return return value or null if void
125 * @param <T> subject type
126 * @param <U> return value type
127 * @throws TestUtilsException if there are reflection errors while calling
128 * the method
129 */
130 public static <T, U> U callMethod(T subject, String methodName,
131 Class<?>[] paramTypes, Object...args) throws TestUtilsException {
132
133 try {
134 @SuppressWarnings("unchecked")
135 Class<T> clazz = (Class<T>) subject.getClass();
136 final Method method;
137 if (paramTypes == null || paramTypes.length == 0) {
138 method = clazz.getDeclaredMethod(methodName);
139 } else {
140 method = clazz.getDeclaredMethod(methodName, paramTypes);
141 }
142 method.setAccessible(true);
143
144 @SuppressWarnings("unchecked")
145 U result = (U) method.invoke(subject, args);
146 return result;
147 } catch (NoSuchMethodException | SecurityException |
148 IllegalAccessException | IllegalArgumentException |
149 InvocationTargetException e) {
150 throw new TestUtilsException("callMethod failed", e);
151 }
152 }
153
154 /**
155 * Calls the method, bypassing scope restriction.
156 *
157 * @param subject Object where the method belongs
158 * @param methodName name of the method to call
159 * @param paramType formal parameter type
160 * @param arg argument
161 * @return return value or null if void
162 * @param <T> subject type
163 * @param <U> return value type
164 * @throws TestUtilsException if there are reflection errors while calling
165 * the method
166 */
167 public static <T, U> U callMethod(T subject, String methodName,
168 Class<?> paramType, Object arg) throws TestUtilsException {
169 return callMethod(subject, methodName, new Class<?>[]{paramType}, arg);
170 }
171
172 /**
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700173 * Triggers an allocation of an object of type T and forces a call to
Jonathan Hart20d8e512014-10-16 11:05:52 -0700174 * the private constructor.
175 *
176 * @param constructor Constructor to call
177 * @param <T> type of the object to create
Thomas Vachuska8cd66a52014-10-30 11:53:07 -0700178 * @return created object of type T
Jonathan Hart20d8e512014-10-16 11:05:52 -0700179 * @throws TestUtilsException if there are reflection errors while calling
180 * the constructor
181 */
182 public static <T> T callConstructor(Constructor<T> constructor)
183 throws TestUtilsException {
184 try {
185 constructor.setAccessible(true);
186 return constructor.newInstance();
187 } catch (InstantiationException | IllegalAccessException |
188 InvocationTargetException error) {
189 throw new TestUtilsException("callConstructor failed", error);
190 }
191 }
192
193 /**
194 * Avoid instantiation.
195 */
196 private TestUtils() {}
197
198 /**
199 * Exception that can be thrown if problems are encountered while executing
200 * the utility method. These are usually problems accessing fields/methods
201 * through reflection. The original exception can be found by examining the
202 * cause.
203 */
Thomas Vachuska2048c1f2017-05-10 19:32:22 -0700204 public static class TestUtilsException extends RuntimeException {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700205
206 private static final long serialVersionUID = 1L;
207
208 /**
209 * Constructs a new exception with the specified detail message and
210 * cause.
211 *
212 * @param message the detail message
213 * @param cause the original cause of this exception
214 */
215 public TestUtilsException(String message, Throwable cause) {
216 super(message, cause);
217 }
218 }
219}