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