001// Licensed under the Apache License, Version 2.0 (the "License"); 002// you may not use this file except in compliance with the License. 003// You may obtain a copy of the License at 004// 005// http://www.apache.org/licenses/LICENSE-2.0 006// 007// Unless required by applicable law or agreed to in writing, software 008// distributed under the License is distributed on an "AS IS" BASIS, 009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 010// See the License for the specific language governing permissions and 011// limitations under the License. 012 013package org.apache.tapestry5.test.ioc; 014 015import org.testng.Assert; 016 017import java.lang.reflect.Field; 018import java.util.ArrayList; 019import java.util.Arrays; 020import java.util.List; 021 022/** 023 * Extra assertions on top of the standard set, packaged as a base class for easy referencing in tests. Also, 024 * utilities for instantiation objects and setting and reading private fields of those objects. 025 * 026 * This class was originally in the tapestry-ioc module as was moved to tapestry-test; the package name was not changed 027 * to ensure backwards compatibility. 028 * 029 * @since 5.2.0 030 * @deprecated In 5.4, with no replacement 031 */ 032public class TestUtils extends Assert 033{ 034 035 /** 036 * Invoked from code that should not be reachable. For example, place a call to unreachable() after invoking a 037 * method that is expected to throw an exception. 038 */ 039 public static void unreachable() 040 { 041 fail("This code should not be reachable."); 042 } 043 044 /** 045 * Asserts that the message property of the throwable contains each of the provided substrings. 046 * 047 * @param t 048 * throwable to check 049 * @param substrings 050 * some number of expected substrings 051 */ 052 public static void assertMessageContains(Throwable t, String... substrings) 053 { 054 String message = t.getMessage(); 055 056 for (String substring : substrings) 057 assertTrue(message.contains(substring), String.format("String '%s' not found in '%s'.", substring, message)); 058 } 059 060 /** 061 * Compares two lists for equality; first all the elements are individually compared for equality (if the lists are 062 * of unequal length, only elements up to the shorter length are compared). Then the length of the lists are 063 * compared. This generally gives 064 * 065 * @param <T> 066 * type of objects to compare 067 * @param actual 068 * actual values to check 069 * @param expected 070 * expected values 071 */ 072 public static <T> void assertListsEquals(List<T> actual, List<T> expected) 073 { 074 int count = Math.min(actual.size(), expected.size()); 075 076 try 077 { 078 for (int i = 0; i < count; i++) 079 { 080 assertEquals(actual.get(i), expected.get(i), String.format("Element #%d.", i)); 081 } 082 083 assertEquals(actual.size(), expected.size(), "List size."); 084 } 085 catch (AssertionError ae) 086 { 087 showLists(actual, expected); 088 089 throw ae; 090 } 091 } 092 093 protected static <T> void showLists(List<T> actual, List<T> expected) 094 { 095 List<String> actualStrings = toStrings(actual); 096 List<String> expectedStrings = toStrings(expected); 097 098 String format = String 099 .format("%%3d: [%%-%ds] [%%-%ds]\n", maxLength(actualStrings), maxLength(expectedStrings)); 100 101 int count = Math.max(actual.size(), expected.size()); 102 103 System.out.flush(); 104 System.err.flush(); 105 106 System.err.println("List results differ (actual vs. expected):"); 107 108 for (int i = 0; i < count; i++) 109 { 110 System.err.printf(format, i, get(actualStrings, i), get(expectedStrings, i)); 111 } 112 } 113 114 private static String get(List<String> list, int index) 115 { 116 if (index < list.size()) 117 return list.get(index); 118 119 return ""; 120 } 121 122 private static int maxLength(List<String> list) 123 { 124 int result = 0; 125 126 for (String s : list) 127 { 128 result = Math.max(result, s.length()); 129 } 130 131 return result; 132 } 133 134 private static <T> List<String> toStrings(List<T> list) 135 { 136 List<String> result = new ArrayList<String>(); 137 138 for (T t : list) 139 { 140 result.add(String.valueOf(t)); 141 } 142 143 return result; 144 } 145 146 /** 147 * Convenience for {@link #assertListsEquals(List, List)}. 148 * 149 * @param <T> 150 * type of objects to compare 151 * @param actual 152 * actual values to check 153 * @param expected 154 * expected values 155 */ 156 public static <T> void assertListsEquals(List<T> actual, T... expected) 157 { 158 assertListsEquals(actual, Arrays.asList(expected)); 159 } 160 161 /** 162 * Convenience for {@link #assertListsEquals(List, List)}. 163 * 164 * @param <T> 165 * type of objects to compare 166 * @param actual 167 * actual values to check 168 * @param expected 169 * expected values 170 */ 171 public static <T> void assertArraysEqual(T[] actual, T... expected) 172 { 173 assertListsEquals(Arrays.asList(actual), expected); 174 } 175 176 /** 177 * Initializes private fields (via reflection). 178 * 179 * @param object 180 * object to be updated 181 * @param fieldValues 182 * string field names and corresponding field values 183 * @return the object 184 */ 185 public static <T> T set(T object, Object... fieldValues) 186 { 187 assert object != null; 188 Class objectClass = object.getClass(); 189 190 for (int i = 0; i < fieldValues.length; i += 2) 191 { 192 String fieldName = (String) fieldValues[i]; 193 Object fieldValue = fieldValues[i + 1]; 194 195 try 196 { 197 Field field = findField(objectClass, fieldName); 198 199 field.setAccessible(true); 200 201 field.set(object, fieldValue); 202 } 203 catch (Exception ex) 204 { 205 throw new RuntimeException(String.format("Unable to set field '%s' of %s to %s: %s", fieldName, object, 206 fieldValue, toMessage(ex)), ex); 207 } 208 } 209 210 return object; 211 } 212 213 /** 214 * Reads the content of a private field. 215 * 216 * @param object 217 * to read the private field from 218 * @param fieldName 219 * name of field to read 220 * @return value stored in the field 221 * @since 5.1.0.5 222 */ 223 public static Object get(Object object, String fieldName) 224 { 225 assert object != null; 226 227 try 228 { 229 Field field = findField(object.getClass(), fieldName); 230 231 field.setAccessible(true); 232 233 return field.get(object); 234 } 235 catch (Exception ex) 236 { 237 throw new RuntimeException(String.format("Unable to read field '%s' of %s: %s", fieldName, object, 238 toMessage(ex)), ex); 239 } 240 } 241 242 private static String toMessage(Throwable exception) 243 { 244 String message = exception.getMessage(); 245 246 if (message != null) 247 return message; 248 249 return exception.getClass().getName(); 250 } 251 252 private static Field findField(Class objectClass, String fieldName) 253 { 254 255 Class cursor = objectClass; 256 257 while (cursor != null) 258 { 259 try 260 { 261 return cursor.getDeclaredField(fieldName); 262 } 263 catch (NoSuchFieldException ex) 264 { 265 // Ignore. 266 } 267 268 cursor = cursor.getSuperclass(); 269 } 270 271 throw new RuntimeException(String.format("Class %s does not contain a field named '%s'.", 272 objectClass.getName(), fieldName)); 273 } 274 275 /** 276 * Creates a new instance of the object using its default constructor, and initializes it (via 277 * {@link #set(Object, Object[])}). 278 * 279 * @param objectType 280 * typeof object to instantiate 281 * @param fieldValues 282 * string field names and corresponding field values 283 * @return the initialized instance 284 */ 285 public static <T> T create(Class<T> objectType, Object... fieldValues) 286 { 287 T result = null; 288 289 try 290 { 291 result = objectType.newInstance(); 292 } 293 catch (Exception ex) 294 { 295 throw new RuntimeException(String.format("Unable to instantiate instance of %s: %s", objectType.getName(), 296 toMessage(ex)), ex); 297 } 298 299 return set(result, fieldValues); 300 } 301 302}