Home | History | Annotate | Download | only in base
      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 {
     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 
     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
     97     public Integer get() {
     98       calls++;
     99       return calls * 10;
    100     }
    101   }
    102 
    103   public void testMemoize() {
    104     CountingSupplier countingSupplier = new CountingSupplier();
    105     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
    106     checkMemoize(countingSupplier, memoizedSupplier);
    107   }
    108 
    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")
    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 
    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 
    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")
    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")
    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")
    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 
    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 
    230   public void testOfInstanceSuppliesNull() {
    231     Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
    232     assertNull(nullSupplier.get());
    233   }
    234 
    235   @GwtIncompatible("Thread")
    236 
    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 
    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")
    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 
    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 
    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")
    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")
    395   public void testNullPointers() throws Exception {
    396     NullPointerTester tester = new NullPointerTester();
    397     tester.testAllPublicStaticMethods(Suppliers.class);
    398   }
    399 }
    400