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