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.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