• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
testCompose()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 
testComposeWithLists()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
get()98     public Integer get() {
99       calls++;
100       return calls * 10;
101     }
102   }
103 
testMemoize()104   public void testMemoize() {
105     CountingSupplier countingSupplier = new CountingSupplier();
106     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
107     checkMemoize(countingSupplier, memoizedSupplier);
108   }
109 
testMemoize_redudantly()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")
testMemoizeSerialized()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 
checkMemoize( CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)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 
testMemoizeExceptionThrown()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")
testMemoizeWithExpiration()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")
testMemoizeWithExpirationSerialized()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")
checkExpiration( CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)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 
testOfInstanceSuppliesSameInstance()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 
testOfInstanceSuppliesNull()231   public void testOfInstanceSuppliesNull() {
232     Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
233     assertNull(nullSupplier.get());
234   }
235 
236   @GwtIncompatible("Thread")
237 
testExpiringMemoizedSupplierThreadSafe()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 
testMemoizedSupplierThreadSafe()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")
testSupplierThreadSafe( Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)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 
testSynchronizedSupplierThreadSafe()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 
testSupplierFunction()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")
testSerialization()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")
testSuppliersNullChecks()396   public void testSuppliersNullChecks() throws Exception {
397     new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class)
398         .testNulls();
399   }
400 
401   @GwtIncompatible("reflection")
testSuppliersSerializable()402   public void testSuppliersSerializable() throws Exception {
403     new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class)
404         .testSerializable();
405   }
406 
testOfInstance_equals()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 
testCompose_equals()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