1 /** 2 * Copyright (C) 2008 Google Inc. 3 * 4 * 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 7 * 8 * 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. 15 */ 16 17 18 package com.google.inject; 19 20 import static com.google.inject.internal.InternalFlags.IncludeStackTraceOption; 21 import static com.google.inject.internal.InternalFlags.getIncludeStackTraceOption; 22 import static junit.framework.Assert.assertEquals; 23 import static junit.framework.Assert.assertNotNull; 24 import static junit.framework.Assert.assertSame; 25 import static junit.framework.Assert.assertTrue; 26 27 import com.google.common.base.Function; 28 import com.google.common.base.Joiner; 29 import com.google.common.collect.ImmutableList; 30 import com.google.common.collect.Iterables; 31 import com.google.common.testing.GcFinalization; 32 33 import junit.framework.Assert; 34 35 import java.io.ByteArrayInputStream; 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 import java.io.NotSerializableException; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 import java.lang.ref.ReferenceQueue; 42 import java.lang.ref.WeakReference; 43 44 /** 45 * @author jessewilson@google.com (Jesse Wilson) 46 */ 47 public class Asserts { Asserts()48 private Asserts() {} 49 50 /** 51 * Returns the String that would appear in an error message for this chain of classes 52 * as modules. 53 */ asModuleChain(Class... classes)54 public static String asModuleChain(Class... classes) { 55 return Joiner.on(" -> ").appendTo(new StringBuilder(" (via modules: "), 56 Iterables.transform(ImmutableList.copyOf(classes), new Function<Class, String>() { 57 @Override 58 public String apply(Class input) { 59 return input.getName(); 60 } 61 })).append(")").toString(); 62 } 63 64 /** 65 * Returns the source file appears in error messages based on {@link 66 * #getIncludeStackTraceOption()} value. 67 */ 68 public static String getDeclaringSourcePart(Class clazz) { 69 if (getIncludeStackTraceOption() == IncludeStackTraceOption.OFF) { 70 return ".configure(Unknown Source"; 71 } 72 return ".configure(" + clazz.getSimpleName() + ".java:"; 73 } 74 75 /** 76 * Returns true if {@link #getIncludeStackTraceOption()} returns {@link 77 * IncludeStackTraceOption#OFF}. 78 */ 79 public static boolean isIncludeStackTraceOff() { 80 return getIncludeStackTraceOption() == IncludeStackTraceOption.OFF; 81 } 82 83 /** 84 * Returns true if {@link #getIncludeStackTraceOption()} returns {@link 85 * IncludeStackTraceOption#COMPLETE}. 86 */ 87 public static boolean isIncludeStackTraceComplete() { 88 return getIncludeStackTraceOption() == IncludeStackTraceOption.COMPLETE; 89 } 90 91 /** 92 * Fails unless {@code expected.equals(actual)}, {@code 93 * actual.equals(expected)} and their hash codes are equal. This is useful 94 * for testing the equals method itself. 95 */ 96 public static void assertEqualsBothWays(Object expected, Object actual) { 97 assertNotNull(expected); 98 assertNotNull(actual); 99 assertEquals("expected.equals(actual)", actual, expected); 100 assertEquals("actual.equals(expected)", expected, actual); 101 assertEquals("hashCode", expected.hashCode(), actual.hashCode()); 102 } 103 104 /** 105 * Fails unless {@code text} includes all {@code substrings}, in order. 106 */ 107 public static void assertContains(String text, String... substrings) { 108 /*if[NO_AOP] 109 // when we strip out bytecode manipulation, we lose the ability to generate some source lines. 110 if (text.contains("(Unknown Source)")) { 111 return; 112 } 113 end[NO_AOP]*/ 114 115 int startingFrom = 0; 116 for (String substring : substrings) { 117 int index = text.indexOf(substring, startingFrom); 118 assertTrue(String.format("Expected \"%s\" to contain substring \"%s\"", text, substring), 119 index >= startingFrom); 120 startingFrom = index + substring.length(); 121 } 122 123 String lastSubstring = substrings[substrings.length - 1]; 124 assertTrue(String.format("Expected \"%s\" to contain substring \"%s\" only once),", 125 text, lastSubstring), text.indexOf(lastSubstring, startingFrom) == -1); 126 } 127 128 /** 129 * Fails unless {@code object} doesn't equal itself when reserialized. 130 */ 131 public static void assertEqualWhenReserialized(Object object) 132 throws IOException { 133 Object reserialized = reserialize(object); 134 assertEquals(object, reserialized); 135 assertEquals(object.hashCode(), reserialized.hashCode()); 136 } 137 138 /** 139 * Fails unless {@code object} has the same toString value when reserialized. 140 */ 141 public static void assertSimilarWhenReserialized(Object object) throws IOException { 142 Object reserialized = reserialize(object); 143 assertEquals(object.toString(), reserialized.toString()); 144 } 145 146 public static <E> E reserialize(E original) throws IOException { 147 try { 148 ByteArrayOutputStream out = new ByteArrayOutputStream(); 149 new ObjectOutputStream(out).writeObject(original); 150 ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); 151 @SuppressWarnings("unchecked") // the reserialized type is assignable 152 E reserialized = (E) new ObjectInputStream(in).readObject(); 153 return reserialized; 154 } catch (ClassNotFoundException e) { 155 throw new RuntimeException(e); 156 } 157 } 158 159 public static void assertNotSerializable(Object object) throws IOException { 160 try { 161 reserialize(object); 162 Assert.fail(); 163 } catch (NotSerializableException expected) { 164 } 165 } 166 167 public static void awaitFullGc() { 168 // GcFinalization *should* do it, but doesn't work well in practice... 169 // so we put a second latch and wait for a ReferenceQueue to tell us. 170 ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 171 WeakReference ref = new WeakReference<Object>(new Object(), queue); 172 GcFinalization.awaitFullGc(); 173 try { 174 assertSame("queue didn't return ref in time", ref, queue.remove(5000)); 175 } catch (IllegalArgumentException e) { 176 throw new RuntimeException(e); 177 } catch (InterruptedException e) { 178 throw new RuntimeException(e); 179 } 180 } 181 182 public static void awaitClear(WeakReference<?> ref) { 183 // GcFinalization *should* do it, but doesn't work well in practice... 184 // so we put a second latch and wait for a ReferenceQueue to tell us. 185 Object data = ref.get(); 186 ReferenceQueue<Object> queue = null; 187 WeakReference extraRef = null; 188 if (data != null) { 189 queue = new ReferenceQueue<Object>(); 190 extraRef = new WeakReference<Object>(data, queue); 191 data = null; 192 } 193 GcFinalization.awaitClear(ref); 194 if (queue != null) { 195 try { 196 assertSame("queue didn't return ref in time", extraRef, queue.remove(5000)); 197 } catch (IllegalArgumentException e) { 198 throw new RuntimeException(e); 199 } catch (InterruptedException e) { 200 throw new RuntimeException(e); 201 } 202 } 203 } 204 } 205