blob: d9bdeb258681694a37babdbbfb906294d2c99c7a [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")
Ray Milkey5b94aea2015-08-05 11:00:55 -070043 Class clazz = subject.getClass();
Jonathan Hart20d8e512014-10-16 11:05:52 -070044 try {
Ray Milkey5b94aea2015-08-05 11:00:55 -070045 while (clazz != null) {
46 try {
47 Field field = clazz.getDeclaredField(fieldName);
48 field.setAccessible(true);
49 field.set(subject, value);
50 break;
51 } catch (NoSuchFieldException ex) {
52 if (clazz == clazz.getSuperclass()) {
53 break;
54 }
55 clazz = clazz.getSuperclass();
56 }
57 }
58 } catch (SecurityException | IllegalArgumentException |
59 IllegalAccessException e) {
Jonathan Hart20d8e512014-10-16 11:05:52 -070060 throw new TestUtilsException("setField failed", e);
61 }
62 }
63
64 /**
65 * Gets the field, bypassing scope restriction.
66 *
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070067 * @param subject Object where the field belongs
Jonathan Hart20d8e512014-10-16 11:05:52 -070068 * @param fieldName name of the field to get
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070069 * @param <T> subject type
70 * @param <U> fieldO value type
Jonathan Hart20d8e512014-10-16 11:05:52 -070071 * @return value of the field.
Jonathan Hart20d8e512014-10-16 11:05:52 -070072 * @throws TestUtilsException if there are reflection errors while getting
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070073 * the field
Jonathan Hart20d8e512014-10-16 11:05:52 -070074 */
75 public static <T, U> U getField(T subject, String fieldName)
76 throws TestUtilsException {
77 try {
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070078 NoSuchFieldException exception = null;
Jonathan Hart20d8e512014-10-16 11:05:52 -070079 @SuppressWarnings("unchecked")
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070080 Class clazz = subject.getClass();
81 while (clazz != null) {
82 try {
83 Field field = clazz.getDeclaredField(fieldName);
84 field.setAccessible(true);
Jonathan Hart20d8e512014-10-16 11:05:52 -070085
Aaron Kruglikov4ce0b042015-10-07 14:04:17 -070086 @SuppressWarnings("unchecked")
87 U result = (U) field.get(subject);
88 return result;
89 } catch (NoSuchFieldException e) {
90 exception = e;
91 if (clazz == clazz.getSuperclass()) {
92 break;
93 }
94 clazz = clazz.getSuperclass();
95 }
96 }
97 throw new TestUtilsException("Field not found. " + fieldName, exception);
98
99 } catch (SecurityException |
100 IllegalArgumentException | IllegalAccessException e) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700101 throw new TestUtilsException("getField failed", e);
102 }
103 }
104
105 /**
106 * Calls the method, bypassing scope restriction.
107 *
108 * @param subject Object where the method belongs
109 * @param methodName name of the method to call
110 * @param paramTypes formal parameter type array
111 * @param args arguments
112 * @return return value or null if void
113 * @param <T> subject type
114 * @param <U> return value type
115 * @throws TestUtilsException if there are reflection errors while calling
116 * the method
117 */
118 public static <T, U> U callMethod(T subject, String methodName,
119 Class<?>[] paramTypes, Object...args) throws TestUtilsException {
120
121 try {
122 @SuppressWarnings("unchecked")
123 Class<T> clazz = (Class<T>) subject.getClass();
124 final Method method;
125 if (paramTypes == null || paramTypes.length == 0) {
126 method = clazz.getDeclaredMethod(methodName);
127 } else {
128 method = clazz.getDeclaredMethod(methodName, paramTypes);
129 }
130 method.setAccessible(true);
131
132 @SuppressWarnings("unchecked")
133 U result = (U) method.invoke(subject, args);
134 return result;
135 } catch (NoSuchMethodException | SecurityException |
136 IllegalAccessException | IllegalArgumentException |
137 InvocationTargetException e) {
138 throw new TestUtilsException("callMethod failed", e);
139 }
140 }
141
142 /**
143 * Calls the method, bypassing scope restriction.
144 *
145 * @param subject Object where the method belongs
146 * @param methodName name of the method to call
147 * @param paramType formal parameter type
148 * @param arg argument
149 * @return return value or null if void
150 * @param <T> subject type
151 * @param <U> return value type
152 * @throws TestUtilsException if there are reflection errors while calling
153 * the method
154 */
155 public static <T, U> U callMethod(T subject, String methodName,
156 Class<?> paramType, Object arg) throws TestUtilsException {
157 return callMethod(subject, methodName, new Class<?>[]{paramType}, arg);
158 }
159
160 /**
Thomas Vachuska7b652ad2014-10-30 14:10:51 -0700161 * Triggers an allocation of an object of type T and forces a call to
Jonathan Hart20d8e512014-10-16 11:05:52 -0700162 * the private constructor.
163 *
164 * @param constructor Constructor to call
165 * @param <T> type of the object to create
Thomas Vachuska8cd66a52014-10-30 11:53:07 -0700166 * @return created object of type T
Jonathan Hart20d8e512014-10-16 11:05:52 -0700167 * @throws TestUtilsException if there are reflection errors while calling
168 * the constructor
169 */
170 public static <T> T callConstructor(Constructor<T> constructor)
171 throws TestUtilsException {
172 try {
173 constructor.setAccessible(true);
174 return constructor.newInstance();
175 } catch (InstantiationException | IllegalAccessException |
176 InvocationTargetException error) {
177 throw new TestUtilsException("callConstructor failed", error);
178 }
179 }
180
181 /**
182 * Avoid instantiation.
183 */
184 private TestUtils() {}
185
186 /**
187 * Exception that can be thrown if problems are encountered while executing
188 * the utility method. These are usually problems accessing fields/methods
189 * through reflection. The original exception can be found by examining the
190 * cause.
191 */
192 public static class TestUtilsException extends Exception {
193
194 private static final long serialVersionUID = 1L;
195
196 /**
197 * Constructs a new exception with the specified detail message and
198 * cause.
199 *
200 * @param message the detail message
201 * @param cause the original cause of this exception
202 */
203 public TestUtilsException(String message, Throwable cause) {
204 super(message, cause);
205 }
206 }
207}