1 /* 2 * Copyright (C) 2007 The Guava Authors 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 package com.google.common.base; 18 19 import static com.google.common.testing.SerializableTester.reserialize; 20 21 import com.google.common.annotations.GwtCompatible; 22 import com.google.common.annotations.GwtIncompatible; 23 import com.google.common.collect.Lists; 24 import com.google.common.testing.ClassSanityTester; 25 import com.google.common.testing.EqualsTester; 26 27 import junit.framework.TestCase; 28 29 import java.io.Serializable; 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.concurrent.TimeUnit; 33 import java.util.concurrent.TimeoutException; 34 import java.util.concurrent.atomic.AtomicInteger; 35 import java.util.concurrent.atomic.AtomicReference; 36 37 /** 38 * Tests com.google.common.base.Suppliers. 39 * 40 * @author Laurence Gonsalves 41 * @author Harry Heymann 42 */ 43 @GwtCompatible(emulated = true) 44 public class SuppliersTest extends TestCase { 45 public void testCompose() { 46 Supplier<Integer> fiveSupplier = new Supplier<Integer>() { 47 @Override 48 public Integer get() { 49 return 5; 50 } 51 }; 52 53 Function<Number, Integer> intValueFunction = 54 new Function<Number, Integer>() { 55 @Override 56 public Integer apply(Number x) { 57 return x.intValue(); 58 } 59 }; 60 61 Supplier<Integer> squareSupplier = Suppliers.compose(intValueFunction, 62 fiveSupplier); 63 64 assertEquals(Integer.valueOf(5), squareSupplier.get()); 65 } 66 67 public void testComposeWithLists() { 68 Supplier<ArrayList<Integer>> listSupplier 69 = new Supplier<ArrayList<Integer>>() { 70 @Override 71 public ArrayList<Integer> get() { 72 return Lists.newArrayList(0); 73 } 74 }; 75 76 Function<List<Integer>, List<Integer>> addElementFunction = 77 new Function<List<Integer>, List<Integer>>() { 78 @Override 79 public List<Integer> apply(List<Integer> list) { 80 ArrayList<Integer> result = Lists.newArrayList(list); 81 result.add(1); 82 return result; 83 } 84 }; 85 86 Supplier<List<Integer>> addSupplier = Suppliers.compose(addElementFunction, 87 listSupplier); 88 89 List<Integer> result = addSupplier.get(); 90 assertEquals(Integer.valueOf(0), result.get(0)); 91 assertEquals(Integer.valueOf(1), result.get(1)); 92 } 93 94 static class CountingSupplier implements Supplier<Integer>, Serializable { 95 private static final long serialVersionUID = 0L; 96 transient int calls = 0; 97 @Override 98 public Integer get() { 99 calls++; 100 return calls * 10; 101 } 102 } 103 104 public void testMemoize() { 105 CountingSupplier countingSupplier = new CountingSupplier(); 106 Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier); 107 checkMemoize(countingSupplier, memoizedSupplier); 108 } 109 110 public void testMemoize_redudantly() { 111 CountingSupplier countingSupplier = new CountingSupplier(); 112 Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier); 113 assertSame(memoizedSupplier, Suppliers.memoize(memoizedSupplier)); 114 } 115 116 @GwtIncompatible("SerializableTester") 117 public void testMemoizeSerialized() { 118 CountingSupplier countingSupplier = new CountingSupplier(); 119 Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier); 120 checkMemoize(countingSupplier, memoizedSupplier); 121 // Calls to the original memoized supplier shouldn't affect its copy. 122 memoizedSupplier.get(); 123 124 Supplier<Integer> copy = reserialize(memoizedSupplier); 125 memoizedSupplier.get(); 126 127 CountingSupplier countingCopy = (CountingSupplier) 128 ((Suppliers.MemoizingSupplier<Integer>) copy).delegate; 129 checkMemoize(countingCopy, copy); 130 } 131 132 private void checkMemoize( 133 CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) { 134 // the underlying supplier hasn't executed yet 135 assertEquals(0, countingSupplier.calls); 136 137 assertEquals(10, (int) memoizedSupplier.get()); 138 139 // now it has 140 assertEquals(1, countingSupplier.calls); 141 142 assertEquals(10, (int) memoizedSupplier.get()); 143 144 // it still should only have executed once due to memoization 145 assertEquals(1, countingSupplier.calls); 146 } 147 148 public void testMemoizeExceptionThrown() { 149 Supplier<Integer> exceptingSupplier = new Supplier<Integer>() { 150 @Override 151 public Integer get() { 152 throw new NullPointerException(); 153 } 154 }; 155 156 Supplier<Integer> memoizedSupplier = Suppliers.memoize(exceptingSupplier); 157 158 // call get() twice to make sure that memoization doesn't interfere 159 // with throwing the exception 160 for (int i = 0; i < 2; i++) { 161 try { 162 memoizedSupplier.get(); 163 fail("failed to throw NullPointerException"); 164 } catch (NullPointerException e) { 165 // this is what should happen 166 } 167 } 168 } 169 170 @GwtIncompatible("Thread.sleep") 171 public void testMemoizeWithExpiration() throws InterruptedException { 172 CountingSupplier countingSupplier = new CountingSupplier(); 173 174 Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration( 175 countingSupplier, 75, TimeUnit.MILLISECONDS); 176 177 checkExpiration(countingSupplier, memoizedSupplier); 178 } 179 180 @GwtIncompatible("Thread.sleep, SerializationTester") 181 public void testMemoizeWithExpirationSerialized() 182 throws InterruptedException { 183 CountingSupplier countingSupplier = new CountingSupplier(); 184 185 Supplier<Integer> memoizedSupplier = Suppliers.memoizeWithExpiration( 186 countingSupplier, 75, TimeUnit.MILLISECONDS); 187 // Calls to the original memoized supplier shouldn't affect its copy. 188 memoizedSupplier.get(); 189 190 Supplier<Integer> copy = reserialize(memoizedSupplier); 191 memoizedSupplier.get(); 192 193 CountingSupplier countingCopy = (CountingSupplier) 194 ((Suppliers.ExpiringMemoizingSupplier<Integer>) copy).delegate; 195 checkExpiration(countingCopy, copy); 196 } 197 198 @GwtIncompatible("Thread.sleep") 199 private void checkExpiration( 200 CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) 201 throws InterruptedException { 202 // the underlying supplier hasn't executed yet 203 assertEquals(0, countingSupplier.calls); 204 205 assertEquals(10, (int) memoizedSupplier.get()); 206 // now it has 207 assertEquals(1, countingSupplier.calls); 208 209 assertEquals(10, (int) memoizedSupplier.get()); 210 // it still should only have executed once due to memoization 211 assertEquals(1, countingSupplier.calls); 212 213 Thread.sleep(150); 214 215 assertEquals(20, (int) memoizedSupplier.get()); 216 // old value expired 217 assertEquals(2, countingSupplier.calls); 218 219 assertEquals(20, (int) memoizedSupplier.get()); 220 // it still should only have executed twice due to memoization 221 assertEquals(2, countingSupplier.calls); 222 } 223 224 public void testOfInstanceSuppliesSameInstance() { 225 Object toBeSupplied = new Object(); 226 Supplier<Object> objectSupplier = Suppliers.ofInstance(toBeSupplied); 227 assertSame(toBeSupplied,objectSupplier.get()); 228 assertSame(toBeSupplied,objectSupplier.get()); // idempotent 229 } 230 231 public void testOfInstanceSuppliesNull() { 232 Supplier<Integer> nullSupplier = Suppliers.ofInstance(null); 233 assertNull(nullSupplier.get()); 234 } 235 236 @GwtIncompatible("Thread") 237 238 public void testExpiringMemoizedSupplierThreadSafe() throws Throwable { 239 Function<Supplier<Boolean>, Supplier<Boolean>> memoizer = 240 new Function<Supplier<Boolean>, Supplier<Boolean>>() { 241 @Override public Supplier<Boolean> apply(Supplier<Boolean> supplier) { 242 return Suppliers.memoizeWithExpiration( 243 supplier, Long.MAX_VALUE, TimeUnit.NANOSECONDS); 244 } 245 }; 246 testSupplierThreadSafe(memoizer); 247 } 248 249 @GwtIncompatible("Thread") 250 251 public void testMemoizedSupplierThreadSafe() throws Throwable { 252 Function<Supplier<Boolean>, Supplier<Boolean>> memoizer = 253 new Function<Supplier<Boolean>, Supplier<Boolean>>() { 254 @Override public Supplier<Boolean> apply(Supplier<Boolean> supplier) { 255 return Suppliers.memoize(supplier); 256 } 257 }; 258 testSupplierThreadSafe(memoizer); 259 } 260 261 @GwtIncompatible("Thread") 262 public void testSupplierThreadSafe( 263 Function<Supplier<Boolean>, Supplier<Boolean>> memoizer) 264 throws Throwable { 265 final AtomicInteger count = new AtomicInteger(0); 266 final AtomicReference<Throwable> thrown = 267 new AtomicReference<Throwable>(null); 268 final int numThreads = 3; 269 final Thread[] threads = new Thread[numThreads]; 270 final long timeout = TimeUnit.SECONDS.toNanos(60); 271 272 final Supplier<Boolean> supplier = new Supplier<Boolean>() { 273 boolean isWaiting(Thread thread) { 274 switch (thread.getState()) { 275 case BLOCKED: 276 case WAITING: 277 case TIMED_WAITING: 278 return true; 279 default: 280 return false; 281 } 282 } 283 284 int waitingThreads() { 285 int waitingThreads = 0; 286 for (Thread thread : threads) { 287 if (isWaiting(thread)) { 288 waitingThreads++; 289 } 290 } 291 return waitingThreads; 292 } 293 294 @Override 295 public Boolean get() { 296 // Check that this method is called exactly once, by the first 297 // thread to synchronize. 298 long t0 = System.nanoTime(); 299 while (waitingThreads() != numThreads - 1) { 300 if (System.nanoTime() - t0 > timeout) { 301 thrown.set(new TimeoutException( 302 "timed out waiting for other threads to block" + 303 " synchronizing on supplier")); 304 break; 305 } 306 Thread.yield(); 307 } 308 count.getAndIncrement(); 309 return Boolean.TRUE; 310 } 311 }; 312 313 final Supplier<Boolean> memoizedSupplier = memoizer.apply(supplier); 314 315 for (int i = 0; i < numThreads; i++) { 316 threads[i] = new Thread() { 317 @Override public void run() { 318 assertSame(Boolean.TRUE, memoizedSupplier.get()); 319 } 320 }; 321 } 322 for (Thread t : threads) { 323 t.start(); 324 } 325 for (Thread t : threads) { 326 t.join(); 327 } 328 329 if (thrown.get() != null) { 330 throw thrown.get(); 331 } 332 assertEquals(1, count.get()); 333 } 334 335 @GwtIncompatible("Thread") 336 337 public void testSynchronizedSupplierThreadSafe() 338 throws InterruptedException { 339 final Supplier<Integer> nonThreadSafe = new Supplier<Integer>() { 340 int counter = 0; 341 @Override 342 public Integer get() { 343 int nextValue = counter + 1; 344 Thread.yield(); 345 counter = nextValue; 346 return counter; 347 } 348 }; 349 350 final int numThreads = 10; 351 final int iterations = 1000; 352 Thread[] threads = new Thread[numThreads]; 353 for (int i = 0; i < numThreads; i++) { 354 threads[i] = new Thread() { 355 @Override public void run() { 356 for (int j = 0; j < iterations; j++) { 357 Suppliers.synchronizedSupplier(nonThreadSafe).get(); 358 } 359 } 360 }; 361 } 362 for (Thread t : threads) { 363 t.start(); 364 } 365 for (Thread t : threads) { 366 t.join(); 367 } 368 369 assertEquals(numThreads * iterations + 1, (int) nonThreadSafe.get()); 370 } 371 372 public void testSupplierFunction() { 373 Supplier<Integer> supplier = Suppliers.ofInstance(14); 374 Function<Supplier<Integer>, Integer> supplierFunction = 375 Suppliers.supplierFunction(); 376 377 assertEquals(14, (int) supplierFunction.apply(supplier)); 378 } 379 380 @GwtIncompatible("SerializationTester") 381 public void testSerialization() { 382 assertEquals( 383 Integer.valueOf(5), reserialize(Suppliers.ofInstance(5)).get()); 384 assertEquals(Integer.valueOf(5), reserialize(Suppliers.compose( 385 Functions.identity(), Suppliers.ofInstance(5))).get()); 386 assertEquals(Integer.valueOf(5), 387 reserialize(Suppliers.memoize(Suppliers.ofInstance(5))).get()); 388 assertEquals(Integer.valueOf(5), 389 reserialize(Suppliers.memoizeWithExpiration( 390 Suppliers.ofInstance(5), 30, TimeUnit.SECONDS)).get()); 391 assertEquals(Integer.valueOf(5), reserialize( 392 Suppliers.synchronizedSupplier(Suppliers.ofInstance(5))).get()); 393 } 394 395 @GwtIncompatible("reflection") 396 public void testSuppliersNullChecks() throws Exception { 397 new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class) 398 .testNulls(); 399 } 400 401 @GwtIncompatible("reflection") 402 public void testSuppliersSerializable() throws Exception { 403 new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class) 404 .testSerializable(); 405 } 406 407 public void testOfInstance_equals() { 408 new EqualsTester() 409 .addEqualityGroup( 410 Suppliers.ofInstance("foo"), Suppliers.ofInstance("foo")) 411 .addEqualityGroup(Suppliers.ofInstance("bar")) 412 .testEquals(); 413 } 414 415 public void testCompose_equals() { 416 new EqualsTester() 417 .addEqualityGroup( 418 Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo")), 419 Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo"))) 420 .addEqualityGroup( 421 Suppliers.compose(Functions.constant(2), Suppliers.ofInstance("foo"))) 422 .addEqualityGroup( 423 Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("bar"))) 424 .testEquals(); 425 } 426 } 427